diff options
Diffstat (limited to 'java')
39 files changed, 2110 insertions, 2100 deletions
diff --git a/java/Android.bp b/java/Android.bp index 9603815a1..1101d7a33 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -72,7 +72,7 @@ bootstrap_go_package { "rro.go", "sdk.go", "sdk_library.go", - "sdk_library_external.go", + "sdk_library_internal.go", "support_libraries.go", "system_modules.go", "systemserver_classpath_fragment.go", @@ -120,4 +120,5 @@ bootstrap_go_package { "test_spec_test.go", ], pluginFor: ["soong_build"], + visibility: ["//visibility:public"], } diff --git a/java/aar.go b/java/aar.go index b5e24c4b2..7d73b03e4 100644 --- a/java/aar.go +++ b/java/aar.go @@ -45,7 +45,7 @@ func RegisterAARBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_library_import", AARImportFactory) ctx.RegisterModuleType("android_library", AndroidLibraryFactory) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator) + ctx.Transition("propagate_rro_enforcement", &propagateRROEnforcementTransitionMutator{}) }) } @@ -151,15 +151,67 @@ type split struct { path android.Path } -// Propagate RRO enforcement flag to static lib dependencies transitively. -func propagateRROEnforcementMutator(ctx android.TopDownMutatorContext) { +// Propagate RRO enforcement flag to static lib dependencies transitively. If EnforceRROGlobally is set then +// all modules will use the "" variant. If specific modules have RRO enforced, then modules (usually apps) with +// RRO enabled will use the "" variation for themselves, but use the "rro" variant of direct and transitive static +// android_library dependencies. +type propagateRROEnforcementTransitionMutator struct{} + +func (p propagateRROEnforcementTransitionMutator) Split(ctx android.BaseModuleContext) []string { + // Never split modules, apps with or without RRO enabled use the "" variant, static android_library dependencies + // will use create the "rro" variant from incoming tranisitons. + return []string{""} +} + +func (p propagateRROEnforcementTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + // Non-static dependencies are not involved in RRO and always use the empty variant. + if ctx.DepTag() != staticLibTag { + return "" + } + m := ctx.Module() - if d, ok := m.(AndroidLibraryDependency); ok && d.IsRROEnforced(ctx) { - ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) { - if a, ok := d.(AndroidLibraryDependency); ok { - a.SetRROEnforcedForDependent(true) - } - }) + if _, ok := m.(AndroidLibraryDependency); ok { + // If RRO is enforced globally don't bother using "rro" variants, the empty variant will have RRO enabled. + if ctx.Config().EnforceRROGlobally() { + return "" + } + + // If RRO is enabled for this module use the "rro" variants of static dependencies. IncomingTransition will + // rewrite this back to "" if the dependency is not an android_library. + if ctx.Config().EnforceRROForModule(ctx.Module().Name()) { + return "rro" + } + } + + return sourceVariation +} + +func (p propagateRROEnforcementTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { + // Propagate the "rro" variant to android_library modules, but use the empty variant for everything else. + if incomingVariation == "rro" { + m := ctx.Module() + if _, ok := m.(AndroidLibraryDependency); ok { + return "rro" + } + return "" + } + + return "" +} + +func (p propagateRROEnforcementTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { + m := ctx.Module() + if d, ok := m.(AndroidLibraryDependency); ok { + if variation == "rro" { + // This is the "rro" variant of a module that has both variants, mark this one as RRO enabled and + // hide it from make to avoid collisions with the non-RRO empty variant. + d.SetRROEnforcedForDependent(true) + m.HideFromMake() + } else if ctx.Config().EnforceRROGlobally() { + // RRO is enabled globally, mark it enabled for this module, but there is only one variant so no + // need to hide it from make. + d.SetRROEnforcedForDependent(true) + } } } diff --git a/java/androidmk.go b/java/androidmk.go index a1bc90494..0539d25aa 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -415,7 +415,7 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { } else { var names []string for _, jniLib := range app.jniLibs { - names = append(names, jniLib.name) + names = append(names, jniLib.name+":"+jniLib.target.Arch.ArchType.Bitness()) } entries.AddStrings("LOCAL_REQUIRED_MODULES", names...) } diff --git a/java/androidmk_test.go b/java/androidmk_test.go index 243a2791e..1d98b180d 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -286,7 +286,7 @@ func TestJniAsRequiredDeps(t *testing.T) { }{ { name: "app", - expected: []string{"libjni"}, + expected: []string{"libjni:64"}, }, { name: "app_embedded", diff --git a/java/app.go b/java/app.go index 4ac42a750..381808a0d 100644 --- a/java/app.go +++ b/java/app.go @@ -83,7 +83,7 @@ type appProperties struct { Package_splits []string // list of native libraries that will be provided in or alongside the resulting jar - Jni_libs []string `android:"arch_variant"` + Jni_libs proptools.Configurable[[]string] `android:"arch_variant"` // if true, use JNI libraries that link against platform APIs even if this module sets // sdk_version. @@ -311,7 +311,7 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { } else { tag = jniInstallTag } - ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...) + ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs.GetOrDefault(ctx, nil)...) } for _, aconfig_declaration := range a.aaptProperties.Flags_packages { ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration) @@ -428,7 +428,7 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { func (a *AndroidApp) checkEmbedJnis(ctx android.BaseModuleContext) { apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) apkInApex := !apexInfo.IsForPlatform() - hasJnis := len(a.appProperties.Jni_libs) > 0 + hasJnis := len(a.appProperties.Jni_libs.GetOrDefault(ctx, nil)) > 0 if apkInApex && hasJnis && !Bool(a.appProperties.Use_embedded_native_libs) { ctx.ModuleErrorf("APK in APEX should have use_embedded_native_libs: true") @@ -586,7 +586,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { if override := ctx.Config().Getenv("OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION"); override != "" { a.aapt.defaultManifestVersion = override } else { - a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion + a.aapt.defaultManifestVersion = ctx.Config().ReleaseDefaultUpdatableModuleVersion() } } @@ -1135,7 +1135,7 @@ func collectJniDeps(ctx android.ModuleContext, return jniLibs, prebuiltJniPackages } -func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) { +func (a *AndroidApp) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) { ctx.WalkDeps(func(child, parent android.Module) bool { isExternal := !a.DepIsInSameApex(ctx, child) if am, ok := child.(android.ApexModule); ok { @@ -1153,7 +1153,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { } depsInfo := android.DepNameToDepInfoMap{} - a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { depName := to.Name() // Skip dependencies that are only available to APEXes; they are developed with updatability @@ -1417,7 +1417,8 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, - a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs) + a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, + a.testProperties.Auto_gen_config, configs, a.testProperties.Test_options.Test_runner_options) a.testConfig = a.FixTestConfig(ctx, testConfig) a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) @@ -1781,16 +1782,15 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext } } - // Skip java_sdk_library dependencies that provide stubs, but not an implementation. - // This will be restricted to optional_uses_libs - if sdklib, ok := m.(SdkLibraryDependency); ok { - if tag == usesLibOptTag && sdklib.DexJarBuildPath(ctx).PathOrNil() == nil { - u.shouldDisableDexpreopt = true - return - } - } - if lib, ok := m.(UsesLibraryDependency); ok { + if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok { + // Skip java_sdk_library dependencies that provide stubs, but not an implementation. + // This will be restricted to optional_uses_libs + if tag == usesLibOptTag && lib.DexJarBuildPath(ctx).PathOrNil() == nil { + u.shouldDisableDexpreopt = true + return + } + } libName := dep if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil { libName = *ulib.ProvidesUsesLib() diff --git a/java/app_import.go b/java/app_import.go index 045a89a34..a54cf2fc3 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -533,10 +533,6 @@ func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android return android.SdkSpecPrivate.ApiLevel } -func (a *AndroidAppImport) LintDepSets() LintDepSets { - return LintDepSets{} -} - var _ android.ApexModule = (*AndroidAppImport)(nil) // Implements android.ApexModule diff --git a/java/app_test.go b/java/app_test.go index ec97a553f..dd672a095 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -530,9 +530,9 @@ func TestUpdatableApps_ApplyDefaultUpdatableModuleVersion(t *testing.T) { `) foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") android.AssertStringDoesContain(t, - "com.android.foo: expected manifest fixer to set override-placeholder-version to android.DefaultUpdatableModuleVersion", + "com.android.foo: expected manifest fixer to set override-placeholder-version to RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION", foo.BuildParams.Args["args"], - fmt.Sprintf("--override-placeholder-version %s", android.DefaultUpdatableModuleVersion), + fmt.Sprintf("--override-placeholder-version %s", testDefaultUpdatableModuleVersion), ) } @@ -1419,26 +1419,31 @@ func TestAndroidResourceProcessor(t *testing.T) { } func TestAndroidResourceOverlays(t *testing.T) { + type moduleAndVariant struct { + module string + variant string + } + testCases := []struct { name string enforceRROTargets []string enforceRROExcludedOverlays []string - resourceFiles map[string][]string - overlayFiles map[string][]string - rroDirs map[string][]string + resourceFiles map[moduleAndVariant][]string + overlayFiles map[moduleAndVariant][]string + rroDirs map[moduleAndVariant][]string }{ { name: "no RRO", enforceRROTargets: nil, enforceRROExcludedOverlays: nil, - resourceFiles: map[string][]string{ - "foo": nil, - "bar": {"bar/res/res/values/strings.xml"}, - "lib": nil, - "lib2": {"lib2/res/res/values/strings.xml"}, + resourceFiles: map[moduleAndVariant][]string{ + {"foo", "android_common"}: nil, + {"bar", "android_common"}: {"bar/res/res/values/strings.xml"}, + {"lib", "android_common"}: nil, + {"lib2", "android_common"}: {"lib2/res/res/values/strings.xml"}, }, - overlayFiles: map[string][]string{ - "foo": { + overlayFiles: map[moduleAndVariant][]string{ + {"foo", "android_common"}: { "out/soong/.intermediates/lib2/android_common/package-res.apk", "out/soong/.intermediates/lib/android_common/package-res.apk", "out/soong/.intermediates/lib3/android_common/package-res.apk", @@ -1447,57 +1452,65 @@ func TestAndroidResourceOverlays(t *testing.T) { "device/vendor/blah/overlay/foo/res/values/strings.xml", "product/vendor/blah/overlay/foo/res/values/strings.xml", }, - "bar": { + {"bar", "android_common"}: { "device/vendor/blah/static_overlay/bar/res/values/strings.xml", "device/vendor/blah/overlay/bar/res/values/strings.xml", }, - "lib": { + {"lib", "android_common"}: { "out/soong/.intermediates/lib2/android_common/package-res.apk", "lib/res/res/values/strings.xml", "device/vendor/blah/overlay/lib/res/values/strings.xml", }, }, - rroDirs: map[string][]string{ - "foo": nil, - "bar": nil, + rroDirs: map[moduleAndVariant][]string{ + {"foo", "android_common"}: nil, + {"bar", "android_common"}: nil, }, }, { name: "enforce RRO on foo", enforceRROTargets: []string{"foo"}, enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"}, - resourceFiles: map[string][]string{ - "foo": nil, - "bar": {"bar/res/res/values/strings.xml"}, - "lib": nil, - "lib2": {"lib2/res/res/values/strings.xml"}, + resourceFiles: map[moduleAndVariant][]string{ + {"foo", "android_common"}: nil, + {"bar", "android_common"}: {"bar/res/res/values/strings.xml"}, + {"lib", "android_common"}: nil, + {"lib", "android_common_rro"}: nil, + {"lib2", "android_common"}: {"lib2/res/res/values/strings.xml"}, + {"lib2", "android_common_rro"}: {"lib2/res/res/values/strings.xml"}, }, - overlayFiles: map[string][]string{ - "foo": { - "out/soong/.intermediates/lib2/android_common/package-res.apk", - "out/soong/.intermediates/lib/android_common/package-res.apk", - "out/soong/.intermediates/lib3/android_common/package-res.apk", + overlayFiles: map[moduleAndVariant][]string{ + {"foo", "android_common"}: { + "out/soong/.intermediates/lib2/android_common_rro/package-res.apk", + "out/soong/.intermediates/lib/android_common_rro/package-res.apk", + "out/soong/.intermediates/lib3/android_common_rro/package-res.apk", "foo/res/res/values/strings.xml", "device/vendor/blah/static_overlay/foo/res/values/strings.xml", }, - "bar": { + {"bar", "android_common"}: { "device/vendor/blah/static_overlay/bar/res/values/strings.xml", "device/vendor/blah/overlay/bar/res/values/strings.xml", }, - "lib": { + {"lib", "android_common"}: { "out/soong/.intermediates/lib2/android_common/package-res.apk", "lib/res/res/values/strings.xml", + "device/vendor/blah/overlay/lib/res/values/strings.xml", + }, + {"lib", "android_common_rro"}: { + "out/soong/.intermediates/lib2/android_common_rro/package-res.apk", + "lib/res/res/values/strings.xml", }, }, - rroDirs: map[string][]string{ - "foo": { + rroDirs: map[moduleAndVariant][]string{ + {"foo", "android_common"}: { "device:device/vendor/blah/overlay/foo/res", "product:product/vendor/blah/overlay/foo/res", "device:device/vendor/blah/overlay/lib/res", }, - "bar": nil, - "lib": {"device:device/vendor/blah/overlay/lib/res"}, + {"bar", "android_common"}: nil, + {"lib", "android_common"}: nil, + {"lib", "android_common_rro"}: {"device:device/vendor/blah/overlay/lib/res"}, }, }, { @@ -1508,35 +1521,35 @@ func TestAndroidResourceOverlays(t *testing.T) { "device/vendor/blah/static_overlay/foo", "device/vendor/blah/static_overlay/bar/res", }, - resourceFiles: map[string][]string{ - "foo": nil, - "bar": {"bar/res/res/values/strings.xml"}, - "lib": nil, - "lib2": {"lib2/res/res/values/strings.xml"}, + resourceFiles: map[moduleAndVariant][]string{ + {"foo", "android_common"}: nil, + {"bar", "android_common"}: {"bar/res/res/values/strings.xml"}, + {"lib", "android_common"}: nil, + {"lib2", "android_common"}: {"lib2/res/res/values/strings.xml"}, }, - overlayFiles: map[string][]string{ - "foo": { + overlayFiles: map[moduleAndVariant][]string{ + {"foo", "android_common"}: { "out/soong/.intermediates/lib2/android_common/package-res.apk", "out/soong/.intermediates/lib/android_common/package-res.apk", "out/soong/.intermediates/lib3/android_common/package-res.apk", "foo/res/res/values/strings.xml", "device/vendor/blah/static_overlay/foo/res/values/strings.xml", }, - "bar": {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"}, - "lib": { + {"bar", "android_common"}: {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"}, + {"lib", "android_common"}: { "out/soong/.intermediates/lib2/android_common/package-res.apk", "lib/res/res/values/strings.xml", }, }, - rroDirs: map[string][]string{ - "foo": { + rroDirs: map[moduleAndVariant][]string{ + {"foo", "android_common"}: { "device:device/vendor/blah/overlay/foo/res", "product:product/vendor/blah/overlay/foo/res", // Lib dep comes after the direct deps "device:device/vendor/blah/overlay/lib/res", }, - "bar": {"device:device/vendor/blah/overlay/bar/res"}, - "lib": {"device:device/vendor/blah/overlay/lib/res"}, + {"bar", "android_common"}: {"device:device/vendor/blah/overlay/bar/res"}, + {"lib", "android_common"}: {"device:device/vendor/blah/overlay/lib/res"}, }, }, } @@ -1621,19 +1634,19 @@ func TestAndroidResourceOverlays(t *testing.T) { for _, o := range list { res := module.MaybeOutput(o) if res.Rule != nil { - // If the overlay is compiled as part of this module (i.e. a .arsc.flat file), + // If the overlay is compiled as part of this moduleAndVariant (i.e. a .arsc.flat file), // verify the inputs to the .arsc.flat rule. files = append(files, res.Inputs.Strings()...) } else { - // Otherwise, verify the full path to the output of the other module + // Otherwise, verify the full path to the output of the other moduleAndVariant files = append(files, o) } } return files } - getResources := func(moduleName string) (resourceFiles, overlayFiles, rroDirs []string) { - module := result.ModuleForTests(moduleName, "android_common") + getResources := func(moduleName, variantName string) (resourceFiles, overlayFiles, rroDirs []string) { + module := result.ModuleForTests(moduleName, variantName) resourceList := module.MaybeOutput("aapt2/res.list") if resourceList.Rule != nil { resourceFiles = resourceListToFiles(module, android.PathsRelativeToTop(resourceList.Inputs)) @@ -1658,21 +1671,33 @@ func TestAndroidResourceOverlays(t *testing.T) { return resourceFiles, overlayFiles, rroDirs } - modules := []string{"foo", "bar", "lib", "lib2"} - for _, module := range modules { - resourceFiles, overlayFiles, rroDirs := getResources(module) + modules := []moduleAndVariant{ + {"foo", "android_common"}, + {"foo", "android_common_rro"}, + {"bar", "android_common"}, + {"bar", "android_common_rro"}, + {"lib", "android_common"}, + {"lib", "android_common_rro"}, + {"lib2", "android_common"}, + {"lib2", "android_common_rro"}, + } + for _, moduleAndVariant := range modules { + if _, exists := testCase.resourceFiles[moduleAndVariant]; !exists { + continue + } + resourceFiles, overlayFiles, rroDirs := getResources(moduleAndVariant.module, moduleAndVariant.variant) - if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[module]) { + if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[moduleAndVariant]) { t.Errorf("expected %s resource files:\n %#v\n got:\n %#v", - module, testCase.resourceFiles[module], resourceFiles) + moduleAndVariant, testCase.resourceFiles[moduleAndVariant], resourceFiles) } - if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[module]) { + if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[moduleAndVariant]) { t.Errorf("expected %s overlay files:\n %#v\n got:\n %#v", - module, testCase.overlayFiles[module], overlayFiles) + moduleAndVariant, testCase.overlayFiles[moduleAndVariant], overlayFiles) } - if !reflect.DeepEqual(rroDirs, testCase.rroDirs[module]) { + if !reflect.DeepEqual(rroDirs, testCase.rroDirs[moduleAndVariant]) { t.Errorf("expected %s rroDirs: %#v\n got:\n %#v", - module, testCase.rroDirs[module], rroDirs) + moduleAndVariant, testCase.rroDirs[moduleAndVariant], rroDirs) } } }) @@ -3241,7 +3266,7 @@ func TestUsesLibraries(t *testing.T) { java_library { name: "static-runtime-helper", srcs: ["a.java"], - libs: ["runtime-library"], + libs: ["runtime-library.impl"], sdk_version: "current", } @@ -3305,7 +3330,7 @@ func TestUsesLibraries(t *testing.T) { name: "app", srcs: ["a.java"], libs: [ - "qux", + "qux.impl", "quuz.stubs" ], static_libs: [ diff --git a/java/base.go b/java/base.go index ef299b279..32bfc17f9 100644 --- a/java/base.go +++ b/java/base.go @@ -83,9 +83,6 @@ type CommonProperties struct { // list of java libraries that will be compiled into the resulting jar Static_libs proptools.Configurable[[]string] `android:"arch_variant"` - // list of java libraries that should not be used to build this module - Exclude_static_libs []string `android:"arch_variant"` - // manifest file to be included in resulting jar Manifest *string `android:"path"` @@ -535,7 +532,8 @@ type Module struct { linter // list of the xref extraction files - kytheFiles android.Paths + kytheFiles android.Paths + kytheKotlinFiles android.Paths hideApexVariantFromMake bool @@ -707,9 +705,6 @@ func setOutputFiles(ctx android.ModuleContext, m Module) { ctx.SetOutputFiles(android.Paths{m.dexer.proguardDictionary.Path()}, ".proguard_map") } ctx.SetOutputFiles(m.properties.Generated_srcjars, ".generated_srcjars") - if m.linter.outputs.xml != nil { - ctx.SetOutputFiles(android.Paths{m.linter.outputs.xml}, ".lint") - } } func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) { @@ -829,7 +824,7 @@ func (j *Module) AvailableFor(what string) bool { } func (j *Module) staticLibs(ctx android.BaseModuleContext) []string { - return android.RemoveListFromList(j.properties.Static_libs.GetOrDefault(ctx, nil), j.properties.Exclude_static_libs) + return j.properties.Static_libs.GetOrDefault(ctx, nil) } func (j *Module) deps(ctx android.BottomUpMutatorContext) { @@ -853,33 +848,6 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { // Add dependency on libraries that provide additional hidden api annotations. ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...) - if ctx.Config().EnforceInterPartitionJavaSdkLibrary() { - // Require java_sdk_library at inter-partition java dependency to ensure stable - // interface between partitions. If inter-partition java_library dependency is detected, - // raise build error because java_library doesn't have a stable interface. - // - // Inputs: - // PRODUCT_ENFORCE_INTER_PARTITION_JAVA_SDK_LIBRARY - // if true, enable enforcement - // PRODUCT_INTER_PARTITION_JAVA_LIBRARY_ALLOWLIST - // exception list of java_library names to allow inter-partition dependency - for idx := range j.properties.Libs { - if libDeps[idx] == nil { - continue - } - - if javaDep, ok := libDeps[idx].(javaSdkLibraryEnforceContext); ok { - // java_sdk_library is always allowed at inter-partition dependency. - // So, skip check. - if _, ok := javaDep.(*SdkLibrary); ok { - continue - } - - j.checkPartitionsForJavaDependency(ctx, "libs", javaDep) - } - } - } - // For library dependencies that are component libraries (like stubs), add the implementation // as a dependency (dexpreopt needs to be against the implementation library, not stubs). for _, dep := range libDeps { @@ -1370,7 +1338,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) - kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) + j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) if ctx.Failed() { return } @@ -1735,8 +1703,12 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath return } + completeStaticLibsImplementationJarsToCombine := completeStaticLibsImplementationJars + if j.shouldInstrument(ctx) { - outputFile = j.instrument(ctx, flags, outputFile, jarName, specs) + instrumentedOutputFile := j.instrument(ctx, flags, outputFile, jarName, specs) + completeStaticLibsImplementationJarsToCombine = android.NewDepSet(android.PREORDER, android.Paths{instrumentedOutputFile}, nil) + outputFile = instrumentedOutputFile } // merge implementation jar with resources if necessary @@ -1744,7 +1716,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath if ctx.Config().UseTransitiveJarsInClasspath() { resourceJars := completeStaticLibsResourceJars.ToList() if len(resourceJars) > 0 { - implementationAndResourcesJarsToCombine = append(resourceJars, completeStaticLibsImplementationJars.ToList()...) + implementationAndResourcesJarsToCombine = append(resourceJars, completeStaticLibsImplementationJarsToCombine.ToList()...) implementationAndResourcesJarsToCombine = append(implementationAndResourcesJarsToCombine, extraDepCombinedJars...) } } else { @@ -1789,14 +1761,14 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath classesJar: outputFile, jarName: jarName, } - if j.GetProfileGuided() && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting() { + if j.GetProfileGuided(ctx) && j.optimizeOrObfuscateEnabled() && !j.EnableProfileRewriting(ctx) { ctx.PropertyErrorf("enable_profile_rewriting", "Enable_profile_rewriting must be true when profile_guided dexpreopt and R8 optimization/obfuscation is turned on. The attached profile should be sourced from an unoptimized/unobfuscated APK.", ) } - if j.EnableProfileRewriting() { - profile := j.GetProfile() - if profile == "" || !j.GetProfileGuided() { + if j.EnableProfileRewriting(ctx) { + profile := j.GetProfile(ctx) + if profile == "" || !j.GetProfileGuided(ctx) { ctx.PropertyErrorf("enable_profile_rewriting", "Profile and Profile_guided must be set when enable_profile_rewriting is true") } params.artProfileInput = &profile @@ -2413,18 +2385,12 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { return } - if dep, ok := module.(SdkLibraryDependency); ok { + if sdkInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { switch tag { - case sdkLibTag, libTag: - depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx)) - deps.classpath = append(deps.classpath, depHeaderJars...) - deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...) - - // TODO: SDK libraries should export a provider with TransitiveClasspathHeaderJars - depHeaderJarsSet := android.NewDepSet(android.PREORDER, depHeaderJars, nil) - transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, depHeaderJarsSet) - case staticLibTag: - ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) + case sdkLibTag, libTag, staticLibTag: + generatingLibsString := android.PrettyConcat( + getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or") + ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString) } } else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { if sdkLinkType != javaPlatform { @@ -2730,7 +2696,7 @@ func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProvid module := ctx.Module() moduleName := module.Name() - ctx.VisitDirectDepsIgnoreBlueprint(func(m android.Module) { + ctx.VisitDirectDeps(func(m android.Module) { tag := ctx.OtherModuleDependencyTag(m) // This logic mirrors that in (*Module).collectDeps above. There are several places // where we explicitly return RenameUseExclude, even though it is the default, to @@ -2753,7 +2719,7 @@ func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProvid if IsJniDepTag(tag) || tag == certificateTag || tag == proguardRaiseTag { return RenameUseExclude, "tags" } - if _, ok := m.(SdkLibraryDependency); ok { + if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok { switch tag { case sdkLibTag, libTag: return RenameUseExclude, "sdklibdep" // matches collectDeps() diff --git a/java/boot_jars.go b/java/boot_jars.go index 6223dede8..3c3bd550c 100644 --- a/java/boot_jars.go +++ b/java/boot_jars.go @@ -21,7 +21,7 @@ import ( // isActiveModule returns true if the given module should be considered for boot // jars, i.e. if it's enabled and the preferred one in case of source and // prebuilt alternatives. -func isActiveModule(ctx android.ConfigAndErrorContext, module android.Module) bool { +func isActiveModule(ctx android.ConfigurableEvaluatorContext, module android.Module) bool { if !module.Enabled(ctx) { return false } diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index fe4cc7685..4fcd40bd3 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -414,6 +414,12 @@ func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleCont // Cross-cutting metadata dependencies are metadata. return false } + // Dependency to the bootclasspath fragment of another apex + // e.g. concsrypt-bootclasspath-fragment --> art-bootclasspath-fragment + if tag == bootclasspathFragmentDepTag { + return false + + } panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag))) } @@ -1099,22 +1105,10 @@ func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx an return &output } +// DEPRECATED: this information is now generated in the context of the top level prebuilt apex. // produceBootImageProfile extracts the boot image profile from the APEX if available. func (module *PrebuiltBootclasspathFragmentModule) produceBootImageProfile(ctx android.ModuleContext) android.WritablePath { - // This module does not provide a boot image profile. - if module.getProfileProviderApex(ctx) == "" { - return nil - } - - di, err := android.FindDeapexerProviderForModule(ctx) - if err != nil { - // An error was found, possibly due to multiple apexes in the tree that export this library - // Defer the error till a client tries to call getProfilePath - module.profilePathErr = err - return nil // An error has been reported by FindDeapexerProviderForModule. - } - - return di.PrebuiltExportPath(ProfileInstallPathInApex) + return android.PathForModuleInstall(ctx, "intentionally_no_longer_supported") } func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path { diff --git a/java/config/Android.bp b/java/config/Android.bp index bfe83ab8c..6217390bb 100644 --- a/java/config/Android.bp +++ b/java/config/Android.bp @@ -17,4 +17,8 @@ bootstrap_go_package { "kotlin.go", "makevars.go", ], + visibility: [ + "//build/soong:__subpackages__", + "//external/error_prone/soong", + ], } diff --git a/java/config/config.go b/java/config/config.go index c28e07032..87703d821 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -97,11 +97,19 @@ func init() { "-JDcom.android.tools.r8.emitRecordAnnotationsInDex", "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex", }, dexerJavaVmFlagsList...), " ")) - pctx.StaticVariable("R8Flags", strings.Join(append([]string{ - "-JXmx4096M", - "-JDcom.android.tools.r8.emitRecordAnnotationsInDex", - "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex", - }, dexerJavaVmFlagsList...), " ")) + + pctx.VariableFunc("R8Flags", func(ctx android.PackageVarContext) string { + r8flags := append([]string{ + "-JXmx4096M", + "-JDcom.android.tools.r8.emitRecordAnnotationsInDex", + "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex", + }, dexerJavaVmFlagsList...) + if r8DumpDir := ctx.Config().Getenv("R8_DUMP_DIRECTORY"); r8DumpDir != "" { + r8flags = append(r8flags, "-JDcom.android.tools.r8.dumpinputtodirectory="+r8DumpDir) + } + return strings.Join(r8flags, " ") + + }) pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{ `-Xmaxerrs 9999999`, @@ -145,6 +153,7 @@ func init() { pctx.SourcePathVariable("JmodCmd", "${JavaToolchain}/jmod") pctx.SourcePathVariable("JrtFsJar", "${JavaHome}/lib/jrt-fs.jar") pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar") + pctx.SourcePathVariable("KotlinKytheExtractor", "prebuilts/build-tools/${hostPrebuiltTag}/bin/kotlinc_extractor") pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime") pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar") diff --git a/java/config/kotlin.go b/java/config/kotlin.go index e5e187cad..302d021db 100644 --- a/java/config/kotlin.go +++ b/java/config/kotlin.go @@ -50,4 +50,11 @@ func init() { }, " ")) pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{}, " ")) + // Use KotlincKytheGlobalFlags to prevent kotlinc version skew issues between android and + // g3 kythe indexers. + // This is necessary because there might be instances of kotlin code in android + // platform that are not fully compatible with the kotlinc used in g3 kythe indexers. + // e.g. uninitialized variables are a warning in 1.*, but an error in 2.* + // https://github.com/JetBrains/kotlin/blob/master/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt#L748 + pctx.StaticVariable("KotlincKytheGlobalFlags", strings.Join([]string{"-language-version 1.9"}, " ")) } diff --git a/java/dex.go b/java/dex.go index 7d42efc9c..e16b05208 100644 --- a/java/dex.go +++ b/java/dex.go @@ -120,7 +120,7 @@ func (d *DexProperties) resourceShrinkingEnabled(ctx android.ModuleContext) bool } func (d *DexProperties) optimizedResourceShrinkingEnabled(ctx android.ModuleContext) bool { - return d.resourceShrinkingEnabled(ctx) && Bool(d.Optimize.Optimized_shrink_resources) + return d.resourceShrinkingEnabled(ctx) && BoolDefault(d.Optimize.Optimized_shrink_resources, ctx.Config().UseOptimizedResourceShrinkingByDefault()) } func (d *dexer) optimizeOrObfuscateEnabled() bool { @@ -220,14 +220,21 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, deps = append(deps, f) } - if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" { + var requestReleaseMode bool + requestReleaseMode, flags = android.RemoveFromList("--release", flags) + + if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" || ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" { flags = append(flags, "--debug") + requestReleaseMode = false } - if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" { - flags = append(flags, - "--debug", - "--verbose") + // Don't strip out debug information for eng builds, unless the target + // explicitly provided the `--release` build flag. This allows certain + // test targets to remain optimized as part of eng test_suites builds. + if requestReleaseMode { + flags = append(flags, "--release") + } else if ctx.Config().Eng() { + flags = append(flags, "--debug") } // Supplying the platform build flag disables various features like API modeling and desugaring. @@ -245,6 +252,16 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err) } + if !Bool(d.dexProperties.No_dex_container) && effectiveVersion.FinalOrFutureInt() >= 36 { + // W is 36, but we have not bumped the SDK version yet, so check for both. + if ctx.Config().PlatformSdkVersion().FinalInt() >= 36 || + ctx.Config().PlatformSdkCodename() == "Wear" { + // TODO(b/329465418): Skip this module since it causes issue with app DRM + if ctx.ModuleName() != "framework-minus-apex" { + flags = append([]string{"-JDcom.android.tools.r8.dexContainerExperiment"}, flags...) + } + } + } // If the specified SDK level is 10000, then configure the compiler to use the // current platform SDK level and to compile the build as a platform build. @@ -374,11 +391,6 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams) // TODO(ccross): if this is an instrumentation test of an obfuscated app, use the // dictionary of the app and move the app from libraryjars to injars. - // Don't strip out debug information for eng builds. - if ctx.Config().Eng() { - r8Flags = append(r8Flags, "--debug") - } - // TODO(b/180878971): missing classes should be added to the relevant builds. // TODO(b/229727645): do not use true as default for Android platform builds. if proptools.BoolDefault(opt.Ignore_warnings, true) { @@ -390,7 +402,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams) r8Flags = append(r8Flags, "--resource-input", d.resourcesInput.Path().String()) r8Deps = append(r8Deps, d.resourcesInput.Path()) r8Flags = append(r8Flags, "--resource-output", d.resourcesOutput.Path().String()) - if Bool(opt.Optimized_shrink_resources) { + if d.dexProperties.optimizedResourceShrinkingEnabled(ctx) { r8Flags = append(r8Flags, "--optimized-resource-shrinking") } } diff --git a/java/dex_test.go b/java/dex_test.go index 4862d06c9..8bc28e678 100644 --- a/java/dex_test.go +++ b/java/dex_test.go @@ -713,3 +713,97 @@ android_app { } }`) } + +func TestDebugReleaseFlags(t *testing.T) { + bp := ` + android_app { + name: "app", + srcs: ["foo.java"], + platform_apis: true, + dxflags: ["%s"] + } + ` + + testcases := []struct { + name string + envVar string + isEng bool + dxFlags string + expectedFlags string + }{ + { + name: "app_no_optimize_dx", + envVar: "NO_OPTIMIZE_DX", + expectedFlags: "--debug", + }, + { + name: "app_release_no_optimize_dx", + envVar: "NO_OPTIMIZE_DX", + dxFlags: "--release", + // Global env vars override explicit dxflags. + expectedFlags: "--debug", + }, + { + name: "app_generate_dex_debug", + envVar: "GENERATE_DEX_DEBUG", + expectedFlags: "--debug", + }, + { + name: "app_release_generate_dex_debug", + envVar: "GENERATE_DEX_DEBUG", + dxFlags: "--release", + // Global env vars override explicit dxflags. + expectedFlags: "--debug", + }, + { + name: "app_eng", + isEng: true, + expectedFlags: "--debug", + }, + { + name: "app_release_eng", + isEng: true, + dxFlags: "--release", + // Eng mode does *not* override explicit dxflags. + expectedFlags: "--release", + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + fixturePreparer := PrepareForTestWithJavaDefaultModules + fixturePreparer = android.GroupFixturePreparers( + fixturePreparer, + android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.Eng = proptools.BoolPtr(tc.isEng) + }, + ), + ) + if tc.envVar != "" { + fixturePreparer = android.GroupFixturePreparers( + fixturePreparer, + android.FixtureMergeEnv(map[string]string{ + tc.envVar: "true", + }), + ) + } + result := fixturePreparer.RunTestWithBp(t, fmt.Sprintf(bp, tc.dxFlags)) + + appR8 := result.ModuleForTests("app", "android_common").Rule("r8") + android.AssertStringDoesContain(t, "expected flag in R8 flags", + appR8.Args["r8Flags"], tc.expectedFlags) + + var unexpectedFlags string + if tc.expectedFlags == "--debug" { + unexpectedFlags = "--release" + } else if tc.expectedFlags == "--release" { + unexpectedFlags = "--debug" + } + if unexpectedFlags != "" { + android.AssertStringDoesNotContain(t, "unexpected flag in R8 flags", + appR8.Args["r8Flags"], unexpectedFlags) + } + }) + } +} diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 4734357ab..63a863497 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -147,25 +147,25 @@ type dexpreopter struct { type DexpreoptProperties struct { Dex_preopt struct { // If false, prevent dexpreopting. Defaults to true. - Enabled *bool + Enabled proptools.Configurable[bool] `android:"replace_instead_of_append"` // If true, generate an app image (.art file) for this module. - App_image *bool + App_image proptools.Configurable[bool] `android:"replace_instead_of_append"` // If true, use a checked-in profile to guide optimization. Defaults to false unless // a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR // that matches the name of this module, in which case it is defaulted to true. - Profile_guided *bool + Profile_guided proptools.Configurable[bool] `android:"replace_instead_of_append"` // If set, provides the path to profile relative to the Android.bp file. If not set, // defaults to searching for a file that matches the name of this module in the default // profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found. - Profile *string `android:"path"` + Profile proptools.Configurable[string] `android:"path,replace_instead_of_append"` // If set to true, r8/d8 will use `profile` as input to generate a new profile that matches // the optimized dex. // The new profile will be subsequently used as the profile to dexpreopt the dex file. - Enable_profile_rewriting *bool + Enable_profile_rewriting proptools.Configurable[bool] `android:"replace_instead_of_append"` } Dex_preopt_result struct { @@ -244,7 +244,7 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext, libName s return true } - if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) { + if !d.dexpreoptProperties.Dex_preopt.Enabled.GetOrDefault(ctx, true) { return true } @@ -433,12 +433,12 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa if d.inputProfilePathOnHost != nil { profileClassListing = android.OptionalPathForPath(d.inputProfilePathOnHost) - } else if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) && !forPrebuiltApex(ctx) { + } else if d.dexpreoptProperties.Dex_preopt.Profile_guided.GetOrDefault(ctx, true) && !forPrebuiltApex(ctx) { // If enable_profile_rewriting is set, use the rewritten profile instead of the checked-in profile - if d.EnableProfileRewriting() { + if d.EnableProfileRewriting(ctx) { profileClassListing = android.OptionalPathForPath(d.GetRewrittenProfile()) profileIsTextListing = true - } else if profile := d.GetProfile(); profile != "" { + } else if profile := d.GetProfile(ctx); profile != "" { // If dex_preopt.profile_guided is not set, default it based on the existence of the // dexprepot.profile option or the profile class listing. profileClassListing = android.OptionalPathForPath( @@ -458,6 +458,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa // Use the dexJar to create a unique scope for each dexJarStem := strings.TrimSuffix(dexJarFile.Base(), dexJarFile.Ext()) + appImage := d.dexpreoptProperties.Dex_preopt.App_image.Get(ctx) + // Full dexpreopt config, used to create dexpreopt build rules. dexpreoptConfig := &dexpreopt.ModuleConfig{ Name: libName, @@ -486,8 +488,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa PreoptBootClassPathDexFiles: dexFiles.Paths(), PreoptBootClassPathDexLocations: dexLocations, - NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true), - ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false), + NoCreateAppImage: !appImage.GetOrDefault(true), + ForceCreateAppImage: appImage.GetOrDefault(false), PresignedPrebuilt: d.isPresignedPrebuilt, } @@ -657,16 +659,16 @@ func (d *dexpreopter) disableDexpreopt() { d.shouldDisableDexpreopt = true } -func (d *dexpreopter) EnableProfileRewriting() bool { - return proptools.Bool(d.dexpreoptProperties.Dex_preopt.Enable_profile_rewriting) +func (d *dexpreopter) EnableProfileRewriting(ctx android.BaseModuleContext) bool { + return d.dexpreoptProperties.Dex_preopt.Enable_profile_rewriting.GetOrDefault(ctx, false) } -func (d *dexpreopter) GetProfile() string { - return proptools.String(d.dexpreoptProperties.Dex_preopt.Profile) +func (d *dexpreopter) GetProfile(ctx android.BaseModuleContext) string { + return d.dexpreoptProperties.Dex_preopt.Profile.GetOrDefault(ctx, "") } -func (d *dexpreopter) GetProfileGuided() bool { - return proptools.Bool(d.dexpreoptProperties.Dex_preopt.Profile_guided) +func (d *dexpreopter) GetProfileGuided(ctx android.BaseModuleContext) bool { + return d.dexpreoptProperties.Dex_preopt.Profile_guided.GetOrDefault(ctx, false) } func (d *dexpreopter) GetRewrittenProfile() android.Path { diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index a2e473469..5c69ff151 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -463,6 +463,7 @@ func dexpreoptBootJarsFactory() android.SingletonModule { func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) { ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory) + ctx.RegisterModuleType("art_boot_images", artBootImagesFactory) ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator).Parallel() }) @@ -601,6 +602,7 @@ func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContex d.defaultBootImage = defaultBootImageConfig(ctx) d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1) var profileInstalls android.RuleBuilderInstalls + var artBootImageHostInstalls android.RuleBuilderInstalls for _, name := range getImageNames() { config := imageConfigs[name] if config != d.defaultBootImage { @@ -616,6 +618,18 @@ func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContex d.bootFrameworkProfile = bootProfile profileInstalls = append(profileInstalls, installs...) } + // Gather the install files of the host variant of the ART boot image. + // These installed files will be used in ART tests. + if config.name == "art" { + for _, variant := range config.variants { + if variant.target.Os != ctx.Config().BuildOS { + // not a host variant + continue + } + artBootImageHostInstalls = append(artBootImageHostInstalls, variant.installs...) + artBootImageHostInstalls = append(artBootImageHostInstalls, variant.vdexInstalls...) + } + } } if len(profileInstalls) > 0 { android.SetProvider(ctx, profileInstallInfoProvider, profileInstallInfo{ @@ -626,6 +640,15 @@ func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContex installFile(ctx, install) } } + // Set a provider containing the install files of the host variant of the ART boot image. + // The actual install rules will be created by `art_boot_images` + android.SetProvider( + ctx, + artBootImageHostInfoProvider, + artBootImageHostInfo{ + installs: artBootImageHostInstalls, + }, + ) } // GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make. @@ -968,6 +991,14 @@ func packageFileForTargetImage(ctx android.ModuleContext, image *bootImageVarian } } +var artBootImageHostInfoProvider = blueprint.NewProvider[artBootImageHostInfo]() + +// artBootImageHostInfo contains the install locations of the host variant of ART boot image +// this contains both the primary and secondary arch locations +type artBootImageHostInfo struct { + installs android.RuleBuilderInstalls +} + // Generate boot image build rules for a specific target. func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) bootImageVariantOutputs { @@ -1186,8 +1217,13 @@ func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles return nil } - defaultProfile := "frameworks/base/config/boot-image-profile.txt" - extraProfile := "frameworks/base/config/boot-image-profile-extra.txt" + defaultProfile := "frameworks/base/boot/boot-image-profile.txt" + // If ART is prebuilt, primarily in next release configs, this will still use + // the profile from source which represent the latest code, so it may not + // correspond to the BCP jars in the prebuilt APEX, but this is the profile we + // have access to. + artProfile := "art/build/boot/boot-image-profile.txt" + extraProfile := "frameworks/base/boot/boot-image-profile-extra.txt" rule := android.NewRuleBuilder(pctx, ctx) @@ -1202,6 +1238,9 @@ func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles // Return nil and continue without profile. return nil } + if path := android.ExistentPathForSource(ctx, artProfile); path.Valid() { + profiles = append(profiles, path.Path()) + } if path := android.ExistentPathForSource(ctx, extraProfile); path.Valid() { profiles = append(profiles, path.Path()) } @@ -1259,7 +1298,7 @@ func bootFrameworkProfileRule(ctx android.ModuleContext, image *bootImageConfig) return nil, nil } - defaultProfile := "frameworks/base/config/boot-profile.txt" + defaultProfile := "frameworks/base/boot/boot-profile.txt" bootFrameworkProfile := android.PathForSource(ctx, defaultProfile) profile := image.dir.Join(ctx, "boot.bprof") @@ -1344,18 +1383,7 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { } image := d.defaultBootImage - if image != nil { - if profileInstallInfo, ok := android.OtherModuleProvider(ctx, d, profileInstallInfoProvider); ok { - ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", profileInstallInfo.profileInstalls.String()) - if profileInstallInfo.profileLicenseMetadataFile.Valid() { - ctx.Strict("DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA", profileInstallInfo.profileLicenseMetadataFile.String()) - } - } - - if SkipDexpreoptBootJars(ctx) { - return - } - + if image != nil && !SkipDexpreoptBootJars(ctx) { global := dexpreopt.GetGlobalConfig(ctx) dexPaths, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp) ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " ")) @@ -1396,3 +1424,70 @@ func (d *dexpreoptBootJars) AndroidMkEntries() []android.AndroidMkEntries { OutputFile: android.OptionalPathForPath(d.bootFrameworkProfile), }} } + +// artBootImages is a thin wrapper around `dex_bootjars`. +// it creates the installation rules for the host variant of the ART boot image. +type artBootImages struct { + android.ModuleBase + + // A non-empty file that will be written as `LOCAL_SOONG_INSTALLED_MODULE` in out/soong/Android-*.mk + outputFile android.OptionalPath +} + +func artBootImagesFactory() android.Module { + m := &artBootImages{} + android.InitAndroidMultiTargetsArchModule(m, android.HostSupported, android.MultilibCommon) + return m +} + +func (dbj *artBootImages) DepsMutator(ctx android.BottomUpMutatorContext) { + // Create a dependency on `dex_bootjars` to access the intermediate locations of host art boot image. + ctx.AddDependency(ctx.Module(), dexpreoptBootJarDepTag, "dex_bootjars") +} + +func (d *artBootImages) GenerateAndroidBuildActions(ctx android.ModuleContext) { + ctx.VisitDirectDepsWithTag(dexpreoptBootJarDepTag, func(m android.Module) { + hostInstallsInfo, ok := android.OtherModuleProvider(ctx, m, artBootImageHostInfoProvider) + if !ok { + ctx.ModuleErrorf("Could not find information about the host variant of ART boot image") + } + installs := d.installFile(ctx, hostInstallsInfo.installs) + if len(installs) > 0 { + d.outputFile = android.OptionalPathForPath(installs[0]) + // Create a phony target that can ART run-tests can depend on. + ctx.Phony(d.Name(), installs...) + } else { + // this might be true e.g. when building with `WITH_DEXPREOPT=false` + // create an empty file so that the `art_boot_images` is known to the packaging system. + d.outputFile = android.OptionalPathForPath(android.PathForModuleOut(ctx, "undefined_art_boot_images")) + } + }) +} + +// Creates an installation rule for host variant of ART boot image files. +// Returns the list of install locations (out/host/linux-x86/...) +func (d *artBootImages) installFile(ctx android.ModuleContext, ruleBuilderInstalls android.RuleBuilderInstalls) android.Paths { + var ret android.Paths + for _, ruleBuilderInstall := range ruleBuilderInstalls { + installDir := android.PathForModuleInstall( + ctx, + strings.TrimPrefix(filepath.Dir(ruleBuilderInstall.To), "/"), + ) + filename := filepath.Base(ruleBuilderInstall.To) + ctx.InstallFile( + installDir, + filename, + ruleBuilderInstall.From, + ) + ret = append(ret, installDir.Join(ctx, filename)) + } + return ret +} + +// Set `OutputFile` expclitly so that this module does not get elided when generating out/soong/Android-*.mk +func (d *artBootImages) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{{ + Class: "ETC", + OutputFile: d.outputFile, + }} +} diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go index 37c54b915..33c682bfa 100644 --- a/java/dexpreopt_config_testing.go +++ b/java/dexpreopt_config_testing.go @@ -1335,8 +1335,6 @@ DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTart=out/soong/dexpreopt_arm64/dex_artjars/andro DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art:out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/boot-framework-foo.art DEXPREOPT_IMAGE_NAMES=art boot mainline -DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof:/system/etc/boot-image.prof out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof -DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-extra1.oat:/apex/art_boot_images/javalib/arm/boot-extra1.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat:/apex/art_boot_images/javalib/arm64/boot-extra1.oat DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat:/apex/art_boot_images/javalib/x86/boot-extra1.oat diff --git a/java/droiddoc.go b/java/droiddoc.go index 2929bb8d9..2980d91de 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -373,8 +373,10 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName())) } case libTag, sdkLibTag: - if dep, ok := module.(SdkLibraryDependency); ok { - deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) + if sdkInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { + generatingLibsString := android.PrettyConcat( + getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or") + ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString) } else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { deps.classpath = append(deps.classpath, dep.HeaderJars...) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) diff --git a/java/fuzz.go b/java/fuzz.go index d37c55804..e5f1f04ee 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -85,10 +85,11 @@ func JavaFuzzFactory() android.Module { func (j *JavaFuzzTest) DepsMutator(ctx android.BottomUpMutatorContext) { if j.Os().Class.String() == deviceString { - j.testProperties.Jni_libs = append(j.testProperties.Jni_libs, artDeps...) + j.testProperties.Jni_libs.AppendSimpleValue(artDeps) } - if len(j.testProperties.Jni_libs) > 0 { + jniLibs := j.testProperties.Jni_libs.GetOrDefault(ctx, nil) + if len(jniLibs) > 0 { if j.fuzzPackagedModule.FuzzProperties.Fuzz_config == nil { config := &fuzz.FuzzConfig{} j.fuzzPackagedModule.FuzzProperties.Fuzz_config = config @@ -98,7 +99,7 @@ func (j *JavaFuzzTest) DepsMutator(ctx android.BottomUpMutatorContext) { j.fuzzPackagedModule.FuzzProperties.Fuzz_config.IsJni = proptools.BoolPtr(true) for _, target := range ctx.MultiTargets() { sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) - ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...) + ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, jniLibs...) } } diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 4144de82b..365005835 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -298,13 +298,12 @@ func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScop // available, or reports an error. func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path { var dexJar OptionalDexJarPath - if sdkLibrary, ok := module.(SdkLibraryDependency); ok { + if sdkLibrary, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { if ctx.Config().ReleaseHiddenApiExportableStubs() { - dexJar = sdkLibrary.SdkApiExportableStubDexJar(ctx, kind) + dexJar = sdkLibrary.ExportableStubDexJarPaths[kind] } else { - dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind) + dexJar = sdkLibrary.EverythingStubDexJarPaths[kind] } - } else if j, ok := module.(UsesLibraryDependency); ok { dexJar = j.DexJarBuildPath(ctx) } else { @@ -853,15 +852,15 @@ func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, conten i.StubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar) } - if sdkLibrary, ok := module.(SdkLibraryDependency); ok { - removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind) + if sdkLibrary, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { + removedTxtFile := sdkLibrary.RemovedTxtFiles[sdkKind] i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...) } } // If the contents includes any java_sdk_library modules then add them to the stubs. for _, module := range contents { - if _, ok := module.(SdkLibraryDependency); ok { + if _, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { // Add information for every possible API scope needed by hidden API. for _, apiScope := range hiddenAPISdkLibrarySupportedScopes { addFromModule(ctx, module, apiScope) diff --git a/java/java.go b/java/java.go index 95f4fd892..661422b54 100644 --- a/java/java.go +++ b/java/java.go @@ -356,12 +356,17 @@ type UsesLibraryDependency interface { // TODO(jungjw): Move this to kythe.go once it's created. type xref interface { XrefJavaFiles() android.Paths + XrefKotlinFiles() android.Paths } func (j *Module) XrefJavaFiles() android.Paths { return j.kytheFiles } +func (j *Module) XrefKotlinFiles() android.Paths { + return j.kytheKotlinFiles +} + func (d dependencyTag) PropagateAconfigValidation() bool { return d.static } @@ -1296,7 +1301,7 @@ type testProperties struct { Test_options TestOptions // Names of modules containing JNI libraries that should be installed alongside the test. - Jni_libs []string + Jni_libs proptools.Configurable[[]string] // Install the test into a folder named for the module in all test suites. Per_testcase_directory *bool @@ -1480,10 +1485,11 @@ func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) { } } - if len(j.testProperties.Jni_libs) > 0 { + jniLibs := j.testProperties.Jni_libs.GetOrDefault(ctx, nil) + if len(jniLibs) > 0 { for _, target := range ctx.MultiTargets() { sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"}) - ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...) + ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, jniLibs...) } } @@ -2607,17 +2613,6 @@ func (a *Import) JacocoReportClassesFile() android.Path { return nil } -func (j *Import) LintDepSets() LintDepSets { - return LintDepSets{} -} - -func (j *Import) getStrictUpdatabilityLinting() bool { - return false -} - -func (j *Import) setStrictUpdatabilityLinting(bool) { -} - func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs.GetOrDefault(ctx, nil)...) @@ -2695,13 +2690,13 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) } } - } else if dep, ok := module.(SdkLibraryDependency); ok { + } else if _, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { switch tag { case libTag, sdkLibTag: - depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx)) - flags.classpath = append(flags.classpath, depHeaderJars...) - transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, - android.NewDepSet(android.PREORDER, depHeaderJars, nil)) + sdkInfo, _ := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider) + generatingLibsString := android.PrettyConcat( + getGeneratingLibs(ctx, j.SdkVersion(ctx), module.Name(), sdkInfo), true, "or") + ctx.ModuleErrorf("cannot depend directly on java_sdk_library %q; try depending on %s instead", module.Name(), generatingLibsString) } } @@ -2813,41 +2808,14 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } if ctx.Device() { - // If this is a variant created for a prebuilt_apex then use the dex implementation jar - // obtained from the associated deapexer module. + // Shared libraries deapexed from prebuilt apexes are no longer supported. + // Set the dexJarBuildPath to a fake path. + // This allows soong analysis pass, but will be an error during ninja execution if there are + // any rdeps. ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) if ai.ForPrebuiltApex { - // Get the path of the dex implementation jar from the `deapexer` module. - di, err := android.FindDeapexerProviderForModule(ctx) - if err != nil { - // An error was found, possibly due to multiple apexes in the tree that export this library - // Defer the error till a client tries to call DexJarBuildPath - j.dexJarFileErr = err - j.initHiddenAPIError(err) - return - } - dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(j.BaseModuleName()) - if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil { - dexJarFile := makeDexJarPathFromPath(dexOutputPath) - j.dexJarFile = dexJarFile - installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, ApexRootRelativePathToJavaLib(j.BaseModuleName())) - j.dexJarInstallFile = installPath - - j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath) - setUncompressDex(ctx, &j.dexpreopter, &j.dexer) - j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex - - if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil { - j.dexpreopter.inputProfilePathOnHost = profilePath - } - - // Initialize the hiddenapi structure. - j.initHiddenAPI(ctx, dexJarFile, outputFile, j.dexProperties.Uncompress_dex) - } else { - // This should never happen as a variant for a prebuilt_apex is only created if the - // prebuilt_apex has been configured to export the java library dex file. - ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName()) - } + j.dexJarFile = makeDexJarPathFromPath(android.PathForModuleInstall(ctx, "intentionally_no_longer_supported")) + j.initHiddenAPI(ctx, j.dexJarFile, outputFile, j.dexProperties.Uncompress_dex) } else if Bool(j.dexProperties.Compile_dex) { sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) if sdkDep.invalidVersion { @@ -3120,21 +3088,10 @@ func (a *DexImport) JacocoReportClassesFile() android.Path { return nil } -func (a *DexImport) LintDepSets() LintDepSets { - return LintDepSets{} -} - func (j *DexImport) IsInstallable() bool { return true } -func (j *DexImport) getStrictUpdatabilityLinting() bool { - return false -} - -func (j *DexImport) setStrictUpdatabilityLinting(bool) { -} - func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(j.properties.Jars) != 1 { ctx.PropertyErrorf("jars", "exactly one jar must be provided") @@ -3304,15 +3261,20 @@ type kytheExtractJavaSingleton struct { func (ks *kytheExtractJavaSingleton) GenerateBuildActions(ctx android.SingletonContext) { var xrefTargets android.Paths + var xrefKotlinTargets android.Paths ctx.VisitAllModules(func(module android.Module) { if javaModule, ok := module.(xref); ok { xrefTargets = append(xrefTargets, javaModule.XrefJavaFiles()...) + xrefKotlinTargets = append(xrefKotlinTargets, javaModule.XrefKotlinFiles()...) } }) // TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets if len(xrefTargets) > 0 { ctx.Phony("xref_java", xrefTargets...) } + if len(xrefKotlinTargets) > 0 { + ctx.Phony("xref_kotlin", xrefKotlinTargets...) + } } var Bool = proptools.Bool @@ -3332,9 +3294,13 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, depName := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(depModule)) var sdkLib *string - if lib, ok := depModule.(SdkLibraryDependency); ok && lib.sharedLibrary() { + if lib, ok := android.OtherModuleProvider(ctx, depModule, SdkLibraryInfoProvider); ok && lib.SharedLibrary { // A shared SDK library. This should be added as a top-level CLC element. sdkLib = &depName + } else if lib, ok := depModule.(SdkLibraryComponentDependency); ok && lib.OptionalSdkLibraryImplementation() != nil { + if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation())+".impl" { + sdkLib = lib.OptionalSdkLibraryImplementation() + } } else if ulib, ok := depModule.(ProvidesUsesLib); ok { // A non-SDK library disguised as an SDK library by the means of `provides_uses_lib` // property. This should be handled in the same way as a shared SDK library. diff --git a/java/java_test.go b/java/java_test.go index e4e6bca9c..db154ce98 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -670,7 +670,7 @@ func TestPrebuilts(t *testing.T) { java_library { name: "foo", srcs: ["a.java", ":stubs-source"], - libs: ["bar", "sdklib"], + libs: ["bar", "sdklib.stubs"], static_libs: ["baz"], } @@ -2454,37 +2454,6 @@ java_test_host { } } -func TestJavaExcludeStaticLib(t *testing.T) { - ctx, _ := testJava(t, ` - java_library { - name: "bar", - } - java_library { - name: "foo", - } - java_library { - name: "baz", - static_libs: [ - "foo", - "bar", - ], - exclude_static_libs: [ - "bar", - ], - } - `) - - // "bar" not included as dependency of "baz" - CheckModuleDependencies(t, ctx, "baz", "android_common", []string{ - `core-lambda-stubs`, - `ext`, - `foo`, - `framework`, - `stable-core-platform-api-stubs-system-modules`, - `stable.core.platform.api.stubs`, - }) -} - func TestJavaLibraryWithResourcesStem(t *testing.T) { ctx, _ := testJavaWithFS(t, ` java_library { @@ -2674,7 +2643,7 @@ func TestDisableFromTextStubForCoverageBuild(t *testing.T) { android.AssertBoolEquals(t, "stub module expected to depend on from-source stub", true, CheckModuleHasDependency(t, result.TestContext, apiScopePublic.stubsLibraryModuleName("foo"), "android_common", - apiScopePublic.sourceStubLibraryModuleName("foo"))) + apiScopePublic.sourceStubsLibraryModuleName("foo"))) android.AssertBoolEquals(t, "stub module expected to not depend on from-text stub", false, CheckModuleHasDependency(t, result.TestContext, @@ -3065,6 +3034,43 @@ func TestJavaLibraryOutputFilesRel(t *testing.T) { "baz.jar", bazOutputPaths[0].Rel()) } +func TestCoverage(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + prepareForTestWithFrameworkJacocoInstrumentation, + PrepareForTestWithTransitiveClasspathEnabled, + ).RunTestWithBp(t, ` + android_app { + name: "foo", + srcs: ["foo.java"], + static_libs: ["android.car"], + platform_apis: true, + } + + // A library in InstrumentFrameworkModules + java_library { + name: "android.car", + srcs: ["android.car.java"], + } + `) + + foo := result.ModuleForTests("foo", "android_common") + androidCar := result.ModuleForTests("android.car", "android_common") + + fooJacoco := foo.Rule("jacoco") + fooCombine := foo.Description("for javac") + + androidCarJacoco := androidCar.Rule("jacoco") + androidCarJavac := androidCar.Rule("javac") + + android.AssertStringEquals(t, "foo instrumentation rule inputs", fooJacoco.Input.String(), fooCombine.Output.String()) + android.AssertStringEquals(t, "android.car instrumentation rule inputs", androidCarJacoco.Input.String(), androidCarJavac.Output.String()) + + // The input to instrumentation for the `foo` app contains the non-instrumented android.car classes. + android.AssertStringListContains(t, "foo combined inputs", fooCombine.Inputs.Strings(), androidCarJavac.Output.String()) + android.AssertStringListDoesNotContain(t, "foo combined inputs", fooCombine.Inputs.Strings(), androidCarJacoco.Output.String()) +} + func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTestOnly []string, expectedTopLevel []string) { t.Helper() actualTrueModules := []string{} @@ -3095,3 +3101,37 @@ func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTe t.Errorf("top-level: Expected but not found: %v, Found but not expected: %v", left, right) } } + +// Test that a dependency edge is created to the "first" variant of a native library listed in `required` of java_binary +func TestNativeRequiredDepOfJavaBinary(t *testing.T) { + findDepsOfModule := func(ctx *android.TestContext, module android.Module, depName string) []blueprint.Module { + var ret []blueprint.Module + ctx.VisitDirectDeps(module, func(dep blueprint.Module) { + if dep.Name() == depName { + ret = append(ret, dep) + } + }) + return ret + } + + bp := cc.GatherRequiredDepsForTest(android.Android) + ` +java_binary { + name: "myjavabin", + main_class: "com.android.MyJava", + required: ["mynativelib"], +} +cc_library_shared { + name: "mynativelib", +} +` + res, _ := testJava(t, bp) + // The first variant installs the native library via the common variant, so check the deps of both variants. + nativeVariantDepsWithDups := findDepsOfModule(res, res.ModuleForTests("myjavabin", "android_arm64_armv8-a").Module(), "mynativelib") + nativeVariantDepsWithDups = append(nativeVariantDepsWithDups, findDepsOfModule(res, res.ModuleForTests("myjavabin", "android_common").Module(), "mynativelib")...) + + nativeVariantDepsUnique := map[blueprint.Module]bool{} + for _, dep := range nativeVariantDepsWithDups { + nativeVariantDepsUnique[dep] = true + } + android.AssertIntEquals(t, "Create a dep on the first variant", 1, len(nativeVariantDepsUnique)) +} diff --git a/java/kotlin.go b/java/kotlin.go index c28bc3f54..f42d16304 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -64,6 +64,28 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports "kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir", "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name") +var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe", + blueprint.RuleParams{ + Command: `rm -rf "$srcJarDir" && mkdir -p "$srcJarDir" && ` + + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` + + `${config.KotlinKytheExtractor} -corpus ${kytheCorpus} --srcs @$out.rsp --srcs @"$srcJarDir/list" $commonSrcFilesList --cp @$classpath -o $out --kotlin_out $outJar ` + + // wrap the additional kotlin args. + // Skip Xbuild file, pass the cp explicitly. + // Skip header jars, those should not have an effect on kythe results. + ` --args '${config.KotlincGlobalFlags} ` + + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + + ` $kotlincFlags -jvm-target $kotlinJvmTarget ` + + `${config.KotlincKytheGlobalFlags}'`, + CommandDeps: []string{ + "${config.KotlinKytheExtractor}", + "${config.ZipSyncCmd}", + }, + Rspfile: "$out.rsp", + RspfileContent: "$in", + }, + "classpath", "kotlincFlags", "commonSrcFilesList", "kotlinJvmTarget", "outJar", "srcJars", "srcJarDir", +) + func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath { if len(commonSrcFiles) > 0 { // The list of common_srcs may be too long to put on the command line, but @@ -81,7 +103,7 @@ func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Path } // kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile. -func kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath, +func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath, srcFiles, commonSrcFiles, srcJars android.Paths, flags javaBuilderFlags) { @@ -127,6 +149,31 @@ func kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile andro "name": kotlinName, }, }) + + // Emit kythe xref rule + if (ctx.Config().EmitXrefRules()) && ctx.Module() == ctx.PrimaryModule() { + extractionFile := outputFile.ReplaceExtension(ctx, "kzip") + args := map[string]string{ + "classpath": classpathRspFile.String(), + "kotlincFlags": flags.kotlincFlags, + "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(), + "outJar": outputFile.String(), + "srcJars": strings.Join(srcJars.Strings(), " "), + "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars.xref").String(), + } + if commonSrcsList.Valid() { + args["commonSrcFilesList"] = "--common_srcs @" + commonSrcsList.String() + } + ctx.Build(pctx, android.BuildParams{ + Rule: kotlinKytheExtract, + Description: "kotlinKythe", + Output: extractionFile, + Inputs: srcFiles, + Implicits: deps, + Args: args, + }) + j.kytheKotlinFiles = append(j.kytheKotlinFiles, extractionFile) + } } var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{Goma: true}, diff --git a/java/lint.go b/java/lint.go index 6782adc5f..2cbefc3bb 100644 --- a/java/lint.go +++ b/java/lint.go @@ -19,6 +19,7 @@ import ( "sort" "strings" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" @@ -90,7 +91,6 @@ type linter struct { compileSdkKind android.SdkKind javaLanguageLevel string kotlinLanguageLevel string - outputs lintOutputs properties LintProperties extraMainlineLintErrors []string compile_data android.Paths @@ -100,68 +100,55 @@ type linter struct { buildModuleReportZip bool } -type lintOutputs struct { - html android.Path - text android.Path - xml android.Path - referenceBaseline android.Path - - depSets LintDepSets -} - -type lintOutputsIntf interface { - lintOutputs() *lintOutputs -} - -type LintDepSetsIntf interface { - LintDepSets() LintDepSets - - // Methods used to propagate strict_updatability_linting values. - GetStrictUpdatabilityLinting() bool - SetStrictUpdatabilityLinting(bool) -} - type LintDepSets struct { - HTML, Text, XML *android.DepSet[android.Path] + HTML, Text, XML, Baseline *android.DepSet[android.Path] } type LintDepSetsBuilder struct { - HTML, Text, XML *android.DepSetBuilder[android.Path] + HTML, Text, XML, Baseline *android.DepSetBuilder[android.Path] } func NewLintDepSetBuilder() LintDepSetsBuilder { return LintDepSetsBuilder{ - HTML: android.NewDepSetBuilder[android.Path](android.POSTORDER), - Text: android.NewDepSetBuilder[android.Path](android.POSTORDER), - XML: android.NewDepSetBuilder[android.Path](android.POSTORDER), + HTML: android.NewDepSetBuilder[android.Path](android.POSTORDER), + Text: android.NewDepSetBuilder[android.Path](android.POSTORDER), + XML: android.NewDepSetBuilder[android.Path](android.POSTORDER), + Baseline: android.NewDepSetBuilder[android.Path](android.POSTORDER), } } -func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder { +func (l LintDepSetsBuilder) Direct(html, text, xml android.Path, baseline android.OptionalPath) LintDepSetsBuilder { l.HTML.Direct(html) l.Text.Direct(text) l.XML.Direct(xml) + if baseline.Valid() { + l.Baseline.Direct(baseline.Path()) + } return l } -func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder { - if depSets.HTML != nil { - l.HTML.Transitive(depSets.HTML) +func (l LintDepSetsBuilder) Transitive(info *LintInfo) LintDepSetsBuilder { + if info.TransitiveHTML != nil { + l.HTML.Transitive(info.TransitiveHTML) + } + if info.TransitiveText != nil { + l.Text.Transitive(info.TransitiveText) } - if depSets.Text != nil { - l.Text.Transitive(depSets.Text) + if info.TransitiveXML != nil { + l.XML.Transitive(info.TransitiveXML) } - if depSets.XML != nil { - l.XML.Transitive(depSets.XML) + if info.TransitiveBaseline != nil { + l.Baseline.Transitive(info.TransitiveBaseline) } return l } func (l LintDepSetsBuilder) Build() LintDepSets { return LintDepSets{ - HTML: l.HTML.Build(), - Text: l.Text.Build(), - XML: l.XML.Build(), + HTML: l.HTML.Build(), + Text: l.Text.Build(), + XML: l.XML.Build(), + Baseline: l.Baseline.Build(), } } @@ -209,24 +196,18 @@ var allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{ }, } -func (l *linter) LintDepSets() LintDepSets { - return l.outputs.depSets -} +var LintProvider = blueprint.NewProvider[*LintInfo]() -func (l *linter) GetStrictUpdatabilityLinting() bool { - return BoolDefault(l.properties.Lint.Strict_updatability_linting, false) -} +type LintInfo struct { + HTML android.Path + Text android.Path + XML android.Path + ReferenceBaseline android.Path -func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) { - l.properties.Lint.Strict_updatability_linting = &strictLinting -} - -var _ LintDepSetsIntf = (*linter)(nil) - -var _ lintOutputsIntf = (*linter)(nil) - -func (l *linter) lintOutputs() *lintOutputs { - return &l.outputs + TransitiveHTML *android.DepSet[android.Path] + TransitiveText *android.DepSet[android.Path] + TransitiveXML *android.DepSet[android.Path] + TransitiveBaseline *android.DepSet[android.Path] } func (l *linter) enabled() bool { @@ -262,7 +243,9 @@ func lintRBEExecStrategy(ctx android.ModuleContext) string { return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy) } -func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path) lintPaths { +func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder, srcsList android.Path, + baselines android.Paths) lintPaths { + projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml") // Lint looks for a lint.xml file next to the project.xml file, give it one. configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml") @@ -325,12 +308,10 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks) cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks) - if l.GetStrictUpdatabilityLinting() { + if Bool(l.properties.Lint.Strict_updatability_linting) && len(baselines) > 0 { // Verify the module does not baseline issues that endanger safe updatability. - if l.properties.Lint.Baseline_filename != nil { - cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename)) - cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks) - } + strictUpdatabilityChecksOutputFile := VerifyStrictUpdatabilityChecks(ctx, baselines) + cmd.Validation(strictUpdatabilityChecksOutputFile) } return lintPaths{ @@ -342,6 +323,22 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru } +func VerifyStrictUpdatabilityChecks(ctx android.ModuleContext, baselines android.Paths) android.Path { + rule := android.NewRuleBuilder(pctx, ctx) + baselineRspFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check_baselines.rsp") + outputFile := android.PathForModuleOut(ctx, "lint_strict_updatability_check.stamp") + rule.Command().Text("rm -f").Output(outputFile) + rule.Command(). + BuiltTool("lint_strict_updatability_checks"). + FlagWithArg("--name ", ctx.ModuleName()). + FlagWithRspFileInputList("--baselines ", baselineRspFile, baselines). + FlagForEachArg("--disallowed_issues ", updatabilityChecks) + rule.Command().Text("touch").Output(outputFile) + rule.Build("lint_strict_updatability_checks", "lint strict updatability checks") + + return outputFile +} + // generateManifest adds a command to the rule to write a simple manifest that contains the // minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest. func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.WritablePath { @@ -411,6 +408,26 @@ func (l *linter) lint(ctx android.ModuleContext) { l.extraLintCheckJars = append(l.extraLintCheckJars, android.PathForSource(ctx, "prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar")) + var baseline android.OptionalPath + if l.properties.Lint.Baseline_filename != nil { + baseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename)) + } + + html := android.PathForModuleOut(ctx, "lint", "lint-report.html") + text := android.PathForModuleOut(ctx, "lint", "lint-report.txt") + xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml") + referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml") + + depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml, baseline) + + ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) { + if info, ok := android.OtherModuleProvider(ctx, dep, LintProvider); ok { + depSetsBuilder.Transitive(info) + } + }) + + depSets := depSetsBuilder.Build() + rule := android.NewRuleBuilder(pctx, ctx). Sbox(android.PathForModuleOut(ctx, "lint"), android.PathForModuleOut(ctx, "lint.sbox.textproto")). @@ -437,20 +454,9 @@ func (l *linter) lint(ctx android.ModuleContext) { srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp") rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList).Implicits(l.compile_data) - lintPaths := l.writeLintProjectXML(ctx, rule, srcsList) + baselines := depSets.Baseline.ToList() - html := android.PathForModuleOut(ctx, "lint", "lint-report.html") - text := android.PathForModuleOut(ctx, "lint", "lint-report.txt") - xml := android.PathForModuleOut(ctx, "lint", "lint-report.xml") - referenceBaseline := android.PathForModuleOut(ctx, "lint", "lint-baseline.xml") - - depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml) - - ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) { - if depLint, ok := dep.(LintDepSetsIntf); ok { - depSetsBuilder.Transitive(depLint.LintDepSets()) - } - }) + lintPaths := l.writeLintProjectXML(ctx, rule, srcsList, baselines) rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) @@ -505,8 +511,8 @@ func (l *linter) lint(ctx android.ModuleContext) { cmd.FlagWithArg("--check ", checkOnly) } - if l.properties.Lint.Baseline_filename != nil { - cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename)) + if baseline.Valid() { + cmd.FlagWithInput("--baseline ", baseline.Path()) } cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline) @@ -530,25 +536,30 @@ func (l *linter) lint(ctx android.ModuleContext) { rule.Build("lint", "lint") - l.outputs = lintOutputs{ - html: html, - text: text, - xml: xml, - referenceBaseline: referenceBaseline, + android.SetProvider(ctx, LintProvider, &LintInfo{ + HTML: html, + Text: text, + XML: xml, + ReferenceBaseline: referenceBaseline, - depSets: depSetsBuilder.Build(), - } + TransitiveHTML: depSets.HTML, + TransitiveText: depSets.Text, + TransitiveXML: depSets.XML, + TransitiveBaseline: depSets.Baseline, + }) if l.buildModuleReportZip { - l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets()) + l.reports = BuildModuleLintReportZips(ctx, depSets, nil) } // Create a per-module phony target to run the lint check. phonyName := ctx.ModuleName() + "-lint" ctx.Phony(phonyName, xml) + + ctx.SetOutputFiles(android.Paths{xml}, ".lint") } -func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths { +func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets, validations android.Paths) android.Paths { htmlList := android.SortedUniquePaths(depSets.HTML.ToList()) textList := android.SortedUniquePaths(depSets.Text.ToList()) xmlList := android.SortedUniquePaths(depSets.XML.ToList()) @@ -558,13 +569,13 @@ func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) a } htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip") - lintZip(ctx, htmlList, htmlZip) + lintZip(ctx, htmlList, htmlZip, validations) textZip := android.PathForModuleOut(ctx, "lint-report-text.zip") - lintZip(ctx, textList, textZip) + lintZip(ctx, textList, textZip, validations) xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") - lintZip(ctx, xmlList, xmlZip) + lintZip(ctx, xmlList, xmlZip, validations) return android.Paths{htmlZip, textZip, xmlZip} } @@ -642,7 +653,7 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { return } - var outputs []*lintOutputs + var outputs []*LintInfo var dirs []string ctx.VisitAllModules(func(m android.Module) { if ctx.Config().KatiEnabled() && !m.ExportedToMake() { @@ -658,14 +669,14 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { } } - if l, ok := m.(lintOutputsIntf); ok { - outputs = append(outputs, l.lintOutputs()) + if lintInfo, ok := android.OtherModuleProvider(ctx, m, LintProvider); ok { + outputs = append(outputs, lintInfo) } }) dirs = android.SortedUniqueStrings(dirs) - zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) { + zip := func(outputPath android.WritablePath, get func(*LintInfo) android.Path) { var paths android.Paths for _, output := range outputs { @@ -674,20 +685,20 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { } } - lintZip(ctx, paths, outputPath) + lintZip(ctx, paths, outputPath, nil) } l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip") - zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html }) + zip(l.htmlZip, func(l *LintInfo) android.Path { return l.HTML }) l.textZip = android.PathForOutput(ctx, "lint-report-text.zip") - zip(l.textZip, func(l *lintOutputs) android.Path { return l.text }) + zip(l.textZip, func(l *LintInfo) android.Path { return l.Text }) l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip") - zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml }) + zip(l.xmlZip, func(l *LintInfo) android.Path { return l.XML }) l.referenceBaselineZip = android.PathForOutput(ctx, "lint-report-reference-baselines.zip") - zip(l.referenceBaselineZip, func(l *lintOutputs) android.Path { return l.referenceBaseline }) + zip(l.referenceBaselineZip, func(l *LintInfo) android.Path { return l.ReferenceBaseline }) ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip) } @@ -703,17 +714,9 @@ var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil) func init() { android.RegisterParallelSingletonType("lint", func() android.Singleton { return &lintSingleton{} }) - - registerLintBuildComponents(android.InitRegistrationContext) -} - -func registerLintBuildComponents(ctx android.RegistrationContext) { - ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel() - }) } -func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) { +func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath, validations android.Paths) { paths = android.SortedUniquePaths(android.CopyOfPaths(paths)) sort.Slice(paths, func(i, j int) bool { @@ -725,19 +728,8 @@ func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android rule.Command().BuiltTool("soong_zip"). FlagWithOutput("-o ", outputPath). FlagWithArg("-C ", android.PathForIntermediates(ctx).String()). - FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths) + FlagWithRspFileInputList("-r ", outputPath.ReplaceExtension(ctx, "rsp"), paths). + Validations(validations) rule.Build(outputPath.Base(), outputPath.Base()) } - -// Enforce the strict updatability linting to all applicable transitive dependencies. -func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) { - m := ctx.Module() - if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() { - ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) { - if a, ok := d.(LintDepSetsIntf); ok { - a.SetStrictUpdatabilityLinting(true) - } - }) - } -} diff --git a/java/lint_test.go b/java/lint_test.go index b51753f71..afe3914ff 100644 --- a/java/lint_test.go +++ b/java/lint_test.go @@ -164,7 +164,7 @@ func TestJavaLintStrictUpdatabilityLinting(t *testing.T) { sdk_version: "current", lint: { strict_updatability_linting: true, - baseline_filename: "lint-baseline.xml", + baseline_filename: "foo_lint_baseline.xml", }, } @@ -176,7 +176,7 @@ func TestJavaLintStrictUpdatabilityLinting(t *testing.T) { min_sdk_version: "29", sdk_version: "current", lint: { - baseline_filename: "lint-baseline.xml", + baseline_filename: "bar_lint_baseline.xml", } } ` @@ -188,18 +188,13 @@ func TestJavaLintStrictUpdatabilityLinting(t *testing.T) { RunTestWithBp(t, bp) foo := result.ModuleForTests("foo", "android_common") - sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, foo.Output("lint.sbox.textproto")) - if !strings.Contains(*sboxProto.Commands[0].Command, - "--baseline lint-baseline.xml --disallowed_issues NewApi") { - t.Error("did not restrict baselining NewApi") - } - - bar := result.ModuleForTests("bar", "android_common") - sboxProto = android.RuleBuilderSboxProtoForTests(t, result.TestContext, bar.Output("lint.sbox.textproto")) - if !strings.Contains(*sboxProto.Commands[0].Command, - "--baseline lint-baseline.xml --disallowed_issues NewApi") { + strictUpdatabilityCheck := foo.Output("lint_strict_updatability_check.stamp") + if !strings.Contains(strictUpdatabilityCheck.RuleParams.Command, + "--disallowed_issues NewApi") { t.Error("did not restrict baselining NewApi") } + android.AssertStringListContains(t, "strict updatability check baseline inputs", strictUpdatabilityCheck.Inputs.Strings(), "foo_lint_baseline.xml") + android.AssertStringListContains(t, "strict updatability check baseline inputs", strictUpdatabilityCheck.Inputs.Strings(), "bar_lint_baseline.xml") } func TestJavaLintDatabaseSelectionFull(t *testing.T) { diff --git a/java/metalava/Android.bp b/java/metalava/Android.bp index ccbd191d3..6bf183296 100644 --- a/java/metalava/Android.bp +++ b/java/metalava/Android.bp @@ -15,4 +15,5 @@ filegroup { name: "metalava-config-files", srcs: ["*-config.xml"], + visibility: ["//visibility:public"], } diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index d794e511b..5bb77542c 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -33,6 +33,7 @@ var ( platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"} platformBootclasspathBootJarDepTag = bootclasspathDependencyTag{name: "platform-boot-jar"} platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"} + platformBootclasspathImplLibDepTag = dependencyTag{name: "impl-lib-tag"} ) type platformBootclasspathModule struct { @@ -111,12 +112,18 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto // Add dependencies on all the ART jars. global := dexpreopt.GetGlobalConfig(ctx) addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art") + + var bootImageModuleNames []string + // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag) + bootImageModuleNames = append(bootImageModuleNames, global.ArtApexJars.CopyOfJars()...) // Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable // APEXes. - addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag) + platformJars := b.platformJars(ctx) + addDependenciesOntoBootImageModules(ctx, platformJars, platformBootclasspathBootJarDepTag) + bootImageModuleNames = append(bootImageModuleNames, platformJars.CopyOfJars()...) // Add dependencies on all the updatable jars, except the ART jars. apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars @@ -127,9 +134,17 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...) // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag) + bootImageModuleNames = append(bootImageModuleNames, apexJars.CopyOfJars()...) // Add dependencies on all the fragments. b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx) + + for _, bootImageModuleName := range bootImageModuleNames { + implLibName := implLibraryModuleName(bootImageModuleName) + if ctx.OtherModuleExists(implLibName) { + ctx.AddFarVariationDependencies(nil, platformBootclasspathImplLibDepTag, implLibName) + } + } } func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) { @@ -166,8 +181,15 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo allModules = append(allModules, apexModules...) b.configuredModules = allModules + // Do not add implLibModule to allModules as the impl lib is only used to collect the + // transitive source files + var implLibModule []android.Module + ctx.VisitDirectDepsWithTag(implLibraryTag, func(m android.Module) { + implLibModule = append(implLibModule, m) + }) + var transitiveSrcFiles android.Paths - for _, module := range allModules { + for _, module := range append(allModules, implLibModule...) { if depInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { if depInfo.TransitiveSrcFiles != nil { transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...) diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index 67ed84e1d..5b145c658 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -110,6 +110,7 @@ func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleCon p.installConfigFile = android.PathForModuleInstall(ctx, "etc", "compatconfig", p.configFile.Base()) rule.Build(configFileName, "Extract compat/compat_config.xml and install it") ctx.InstallFile(p.installDirPath, p.configFile.Base(), p.configFile) + ctx.SetOutputFiles(android.Paths{p.configFile}, "") } func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 00613eee3..527e479f2 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -124,8 +124,8 @@ func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string, allowIncr return } -func prebuiltApiModuleName(mctx android.LoadHookContext, module, scope, version string) string { - return fmt.Sprintf("%s_%s_%s_%s", mctx.ModuleName(), scope, version, module) +func prebuiltApiModuleName(moduleName, module, scope, version string) string { + return fmt.Sprintf("%s_%s_%s_%s", moduleName, scope, version, module) } func createImport(mctx android.LoadHookContext, module, scope, version, path, sdkVersion string, compileDex bool) { props := struct { @@ -135,7 +135,7 @@ func createImport(mctx android.LoadHookContext, module, scope, version, path, sd Installable *bool Compile_dex *bool }{ - Name: proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version)), + Name: proptools.StringPtr(prebuiltApiModuleName(mctx.ModuleName(), module, scope, version)), Jars: []string{path}, Sdk_version: proptools.StringPtr(sdkVersion), Installable: proptools.BoolPtr(false), @@ -257,8 +257,8 @@ func createSystemModules(mctx android.LoadHookContext, version, scope string) { Name *string Libs []string }{} - props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, "system_modules", scope, version)) - props.Libs = append(props.Libs, prebuiltApiModuleName(mctx, "core-for-system-modules", scope, version)) + props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx.ModuleName(), "system_modules", scope, version)) + props.Libs = append(props.Libs, prebuiltApiModuleName(mctx.ModuleName(), "core-for-system-modules", scope, version)) mctx.CreateModule(systemModulesImportFactory, &props) } diff --git a/java/ravenwood.go b/java/ravenwood.go index bb136cf6e..4c9fdc212 100644 --- a/java/ravenwood.go +++ b/java/ravenwood.go @@ -33,8 +33,8 @@ func RegisterRavenwoodBuildComponents(ctx android.RegistrationContext) { var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"} var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"} var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"} -var ravenwoodDataTag = dependencyTag{name: "ravenwooddata"} var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"} +var ravenwoodTestInstResourceApkTag = dependencyTag{name: "ravenwoodtest-inst-res-apk"} const ravenwoodUtilsName = "ravenwood-utils" const ravenwoodRuntimeName = "ravenwood-runtime" @@ -54,14 +54,20 @@ func getLibPath(archType android.ArchType) string { } type ravenwoodTestProperties struct { - Jni_libs []string + Jni_libs proptools.Configurable[[]string] // Specify another android_app module here to copy it to the test directory, so that - // the ravenwood test can access it. + // the ravenwood test can access it. This APK will be loaded as resources of the test + // target app. // TODO: For now, we simply refer to another android_app module and copy it to the // test directory. Eventually, android_ravenwood_test should support all the resource // related properties and build resources from the `res/` directory. Resource_apk *string + + // Specify another android_app module here to copy it to the test directory, so that + // the ravenwood test can access it. This APK will be loaded as resources of the test + // instrumentation app itself. + Inst_resource_apk *string } type ravenwoodTest struct { @@ -120,7 +126,7 @@ func (r *ravenwoodTest) DepsMutator(ctx android.BottomUpMutatorContext) { } // Add jni libs - for _, lib := range r.ravenwoodTestProperties.Jni_libs { + for _, lib := range r.ravenwoodTestProperties.Jni_libs.GetOrDefault(ctx, nil) { ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) } @@ -128,6 +134,10 @@ func (r *ravenwoodTest) DepsMutator(ctx android.BottomUpMutatorContext) { if resourceApk := proptools.String(r.ravenwoodTestProperties.Resource_apk); resourceApk != "" { ctx.AddVariationDependencies(nil, ravenwoodTestResourceApkTag, resourceApk) } + + if resourceApk := proptools.String(r.ravenwoodTestProperties.Inst_resource_apk); resourceApk != "" { + ctx.AddVariationDependencies(nil, ravenwoodTestInstResourceApkTag, resourceApk) + } } func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -195,13 +205,16 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks") - if resApk := ctx.GetDirectDepsWithTag(ravenwoodTestResourceApkTag); len(resApk) > 0 { - for _, installFile := range android.OtherModuleProviderOrDefault( - ctx, resApk[0], android.InstallFilesProvider).InstallFiles { - installResApk := ctx.InstallFile(resApkInstallPath, "ravenwood-res.apk", installFile) + + copyResApk := func(tag blueprint.DependencyTag, toFileName string) { + if resApk := ctx.GetDirectDepsWithTag(tag); len(resApk) > 0 { + installFile := android.OutputFileForModule(ctx, resApk[0], "") + installResApk := ctx.InstallFile(resApkInstallPath, toFileName, installFile) installDeps = append(installDeps, installResApk) } } + copyResApk(ravenwoodTestResourceApkTag, "ravenwood-res.apk") + copyResApk(ravenwoodTestInstResourceApkTag, "ravenwood-inst-res.apk") // Install our JAR with all dependencies ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...) @@ -225,10 +238,13 @@ func (r *ravenwoodTest) AndroidMkEntries() []android.AndroidMkEntries { type ravenwoodLibgroupProperties struct { Libs []string - Jni_libs []string + Jni_libs proptools.Configurable[[]string] // We use this to copy framework-res.apk to the ravenwood runtime directory. - Data []string + Data []string `android:"path,arch_variant"` + + // We use this to copy font files to the ravenwood runtime directory. + Fonts []string `android:"path,arch_variant"` } type ravenwoodLibgroup struct { @@ -264,12 +280,9 @@ func (r *ravenwoodLibgroup) DepsMutator(ctx android.BottomUpMutatorContext) { for _, lib := range r.ravenwoodLibgroupProperties.Libs { ctx.AddVariationDependencies(nil, ravenwoodLibContentTag, lib) } - for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs { + for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs.GetOrDefault(ctx, nil) { ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) } - for _, data := range r.ravenwoodLibgroupProperties.Data { - ctx.AddVariationDependencies(nil, ravenwoodDataTag, data) - } } func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -309,12 +322,17 @@ func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContex } dataInstallPath := installPath.Join(ctx, "ravenwood-data") - for _, data := range r.ravenwoodLibgroupProperties.Data { - libModule := ctx.GetDirectDepWithTag(data, ravenwoodDataTag) - file := android.OutputFileForModule(ctx, libModule, "") + data := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Data) + for _, file := range data { ctx.InstallFile(dataInstallPath, file.Base(), file) } + fontsInstallPath := installPath.Join(ctx, "fonts") + fonts := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Fonts) + for _, file := range fonts { + ctx.InstallFile(fontsInstallPath, file.Base(), file) + } + // Normal build should perform install steps ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install")) } diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go index d26db930d..753a118e9 100644 --- a/java/ravenwood_test.go +++ b/java/ravenwood_test.go @@ -19,6 +19,7 @@ import ( "testing" "android/soong/android" + "android/soong/etc" ) var prepareRavenwoodRuntime = android.GroupFixturePreparers( @@ -59,11 +60,19 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( } android_app { name: "app1", - sdk_version: "current", + sdk_version: "current", } android_app { name: "app2", - sdk_version: "current", + sdk_version: "current", + } + android_app { + name: "app3", + sdk_version: "current", + } + prebuilt_font { + name: "Font.ttf", + src: "Font.ttf", } android_ravenwood_libgroup { name: "ravenwood-runtime", @@ -76,7 +85,10 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( "ravenwood-runtime-jni2", ], data: [ - "app1", + ":app1", + ], + fonts: [ + ":Font.ttf" ], } android_ravenwood_libgroup { @@ -97,6 +109,7 @@ func TestRavenwoodRuntime(t *testing.T) { ctx := android.GroupFixturePreparers( PrepareForIntegrationTestWithJava, + etc.PrepareForTestWithPrebuiltEtc, prepareRavenwoodRuntime, ).RunTest(t) @@ -114,6 +127,7 @@ func TestRavenwoodRuntime(t *testing.T) { runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so") runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so") runtime.Output(installPathPrefix + "/ravenwood-runtime/ravenwood-data/app1.apk") + runtime.Output(installPathPrefix + "/ravenwood-runtime/fonts/Font.ttf") utils := ctx.ModuleForTests("ravenwood-utils", "android_common") utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar") } @@ -125,29 +139,30 @@ func TestRavenwoodTest(t *testing.T) { ctx := android.GroupFixturePreparers( PrepareForIntegrationTestWithJava, + etc.PrepareForTestWithPrebuiltEtc, prepareRavenwoodRuntime, ).RunTestWithBp(t, ` - cc_library_shared { - name: "jni-lib1", - host_supported: true, - srcs: ["jni.cpp"], - } - cc_library_shared { - name: "jni-lib2", - host_supported: true, - srcs: ["jni.cpp"], - stem: "libblue", - shared_libs: [ - "jni-lib3", - ], - } - cc_library_shared { - name: "jni-lib3", - host_supported: true, - srcs: ["jni.cpp"], - stem: "libpink", - } - android_ravenwood_test { + cc_library_shared { + name: "jni-lib1", + host_supported: true, + srcs: ["jni.cpp"], + } + cc_library_shared { + name: "jni-lib2", + host_supported: true, + srcs: ["jni.cpp"], + stem: "libblue", + shared_libs: [ + "jni-lib3", + ], + } + cc_library_shared { + name: "jni-lib3", + host_supported: true, + srcs: ["jni.cpp"], + stem: "libpink", + } + android_ravenwood_test { name: "ravenwood-test", srcs: ["Test.java"], jni_libs: [ @@ -156,6 +171,7 @@ func TestRavenwoodTest(t *testing.T) { "ravenwood-runtime-jni2", ], resource_apk: "app2", + inst_resource_apk: "app3", sdk_version: "test_current", } `) @@ -183,6 +199,7 @@ func TestRavenwoodTest(t *testing.T) { module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so") module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so") module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk") + module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-inst-res.apk") // ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted. for _, o := range module.AllOutputs() { diff --git a/java/robolectric.go b/java/robolectric.go index 374fc5f78..30c720352 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -76,7 +76,7 @@ type robolectricProperties struct { // Use strict mode to limit access of Robolectric API directly. See go/roboStrictMode Strict_mode *bool - Jni_libs []string + Jni_libs proptools.Configurable[[]string] } type robolectricTest struct { @@ -131,7 +131,7 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), roboRuntimesTag, "robolectric-android-all-prebuilts") - for _, lib := range r.robolectricProperties.Jni_libs { + for _, lib := range r.robolectricProperties.Jni_libs.GetOrDefault(ctx, nil) { ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) } } diff --git a/java/rro_test.go b/java/rro_test.go index 742c83982..4d791305e 100644 --- a/java/rro_test.go +++ b/java/rro_test.go @@ -282,7 +282,7 @@ func TestEnforceRRO_propagatesToDependencies(t *testing.T) { enforceRROTargets: []string{"foo"}, rroDirs: map[string][]string{ "foo": {"product/vendor/blah/overlay/lib2/res"}, - "bar": {"product/vendor/blah/overlay/lib2/res"}, + "bar": nil, }, }, } diff --git a/java/sdk_library.go b/java/sdk_library.go index b7aa4e56d..f30877258 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -29,11 +29,6 @@ import ( "android/soong/android" "android/soong/dexpreopt" - "android/soong/etc" -) - -const ( - sdkXmlFileSuffix = ".xml" ) // A tag to associated a dependency with a specific api scope. @@ -248,7 +243,7 @@ func (scope *apiScope) apiLibraryModuleName(baseName string) string { return scope.stubsLibraryModuleName(baseName) + ".from-text" } -func (scope *apiScope) sourceStubLibraryModuleName(baseName string) string { +func (scope *apiScope) sourceStubsLibraryModuleName(baseName string) string { return scope.stubsLibraryModuleName(baseName) + ".from-source" } @@ -268,10 +263,6 @@ func (scope *apiScope) stubsSourceModuleName(baseName string) string { return baseName + ".stubs.source" + scope.moduleSuffix } -func (scope *apiScope) apiModuleName(baseName string) string { - return baseName + ".api" + scope.moduleSuffix -} - func (scope *apiScope) String() string { return scope.name } @@ -830,16 +821,6 @@ func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, } type commonToSdkLibraryAndImportProperties struct { - // The naming scheme to use for the components that this module creates. - // - // If not specified then it defaults to "default". - // - // This is a temporary mechanism to simplify conversion from separate modules for each - // component that follow a different naming pattern to the default one. - // - // TODO(b/155480189) - Remove once naming inconsistencies have been resolved. - Naming_scheme *string - // Specifies whether this module can be used as an Android shared library; defaults // to true. // @@ -915,8 +896,6 @@ type commonToSdkLibraryAndImport struct { scopePaths map[*apiScope]*scopePaths - namingScheme sdkLibraryComponentNamingScheme - commonSdkLibraryProperties commonToSdkLibraryAndImportProperties // Paths to commonSdkLibraryProperties.Doctag_files @@ -943,16 +922,7 @@ func (c *commonToSdkLibraryAndImport) initCommon(module commonSdkLibraryAndImpor c.initSdkLibraryComponent(module) } -func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool { - schemeProperty := proptools.StringDefault(c.commonSdkLibraryProperties.Naming_scheme, "default") - switch schemeProperty { - case "default": - c.namingScheme = &defaultNamingScheme{} - default: - ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty) - return false - } - +func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied() bool { namePtr := proptools.StringPtr(c.module.RootLibraryName()) c.sdkLibraryComponentProperties.SdkLibraryName = namePtr @@ -974,62 +944,32 @@ func (c *commonToSdkLibraryAndImport) uniqueApexVariations() bool { return c.sharedLibrary() } -func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.ModuleContext) { +func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.ModuleContext) SdkLibraryInfo { c.doctagPaths = android.PathsForModuleSrc(ctx, c.commonSdkLibraryProperties.Doctag_files) -} - -func (c *commonToSdkLibraryAndImport) getImplLibraryModule() *Library { - return c.implLibraryModule -} - -// Module name of the runtime implementation library -func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string { - return c.module.RootLibraryName() + ".impl" -} - -// Module name of the XML file for the lib -func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string { - return c.module.RootLibraryName() + sdkXmlFileSuffix -} - -// Name of the java_library module that compiles the stubs source. -func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.RootLibraryName() - return c.namingScheme.stubsLibraryModuleName(apiScope, baseName) -} -// Name of the java_library module that compiles the exportable stubs source. -func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.RootLibraryName() - return c.namingScheme.exportableStubsLibraryModuleName(apiScope, baseName) -} - -// Name of the droidstubs module that generates the stubs source and may also -// generate/check the API. -func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string { - baseName := c.module.RootLibraryName() - return c.namingScheme.stubsSourceModuleName(apiScope, baseName) -} - -// Name of the java_api_library module that generates the from-text stubs source -// and compiles to a jar file. -func (c *commonToSdkLibraryAndImport) apiLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.RootLibraryName() - return c.namingScheme.apiLibraryModuleName(apiScope, baseName) -} - -// Name of the java_library module that compiles the stubs -// generated from source Java files. -func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.RootLibraryName() - return c.namingScheme.sourceStubsLibraryModuleName(apiScope, baseName) -} + everythingStubPaths := make(map[android.SdkKind]OptionalDexJarPath) + exportableStubPaths := make(map[android.SdkKind]OptionalDexJarPath) + removedApiFilePaths := make(map[android.SdkKind]android.OptionalPath) + for kind := android.SdkNone; kind <= android.SdkPrivate; kind += 1 { + everythingStubPath := makeUnsetDexJarPath() + exportableStubPath := makeUnsetDexJarPath() + removedApiFilePath := android.OptionalPath{} + if scopePath := c.findClosestScopePath(sdkKindToApiScope(kind)); scopePath != nil { + everythingStubPath = scopePath.stubsDexJarPath + exportableStubPath = scopePath.exportableStubsDexJarPath + removedApiFilePath = scopePath.removedApiFilePath + } + everythingStubPaths[kind] = everythingStubPath + exportableStubPaths[kind] = exportableStubPath + removedApiFilePaths[kind] = removedApiFilePath + } -// Name of the java_library module that compiles the exportable stubs -// generated from source Java files. -func (c *commonToSdkLibraryAndImport) exportableSourceStubsLibraryModuleName(apiScope *apiScope) string { - baseName := c.module.RootLibraryName() - return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName) + return SdkLibraryInfo{ + EverythingStubDexJarPaths: everythingStubPaths, + ExportableStubDexJarPaths: exportableStubPaths, + RemovedTxtFiles: removedApiFilePaths, + SharedLibrary: c.sharedLibrary(), + } } // The component names for different outputs of the java_sdk_library. @@ -1103,44 +1043,6 @@ func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *sco return nil } -func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { - - // If a specific numeric version has been requested then use prebuilt versions of the sdk. - if !sdkVersion.ApiLevel.IsPreview() { - return PrebuiltJars(ctx, c.module.RootLibraryName(), 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 { - apiScope := sdkKindToApiScope(kind) - - paths := c.findClosestScopePath(apiScope) - if paths == nil { - var scopes []string - for _, s := range AllApiScopes { - if c.findScopePaths(s) != nil { - scopes = append(scopes, s.name) - } - } - ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.RootLibraryName(), scopes) - return nil - } - - return paths -} - // sdkKindToApiScope maps from android.SdkKind to apiScope. func sdkKindToApiScope(kind android.SdkKind) *apiScope { var apiScope *apiScope @@ -1159,37 +1061,6 @@ func sdkKindToApiScope(kind android.SdkKind) *apiScope { return apiScope } -// to satisfy SdkLibraryDependency interface -func (c *commonToSdkLibraryAndImport) SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath { - paths := c.selectScopePaths(ctx, kind) - if paths == nil { - return makeUnsetDexJarPath() - } - - return paths.stubsDexJarPath -} - -// to satisfy SdkLibraryDependency interface -func (c *commonToSdkLibraryAndImport) SdkApiExportableStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath { - paths := c.selectScopePaths(ctx, kind) - if paths == nil { - return makeUnsetDexJarPath() - } - - return paths.exportableStubsDexJarPath -} - -// to satisfy SdkLibraryDependency interface -func (c *commonToSdkLibraryAndImport) SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath { - apiScope := sdkKindToApiScope(kind) - paths := c.findScopePaths(apiScope) - if paths == nil { - return android.OptionalPath{} - } - - return paths.removedApiFilePath -} - func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} { componentProps := &struct { SdkLibraryName *string @@ -1280,33 +1151,43 @@ var _ SdkLibraryComponentDependency = (*Import)(nil) var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil) var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil) -// Provides access to sdk_version related files, e.g. header and implementation jars. -type SdkLibraryDependency interface { - SdkLibraryComponentDependency +type SdkLibraryInfo struct { + // GeneratingLibs is the names of the library modules that this sdk library + // generates. Note that this only includes the name of the modules that other modules can + // depend on, and is not a holistic list of generated modules. + GeneratingLibs []string - // Get the header jars appropriate for the supplied sdk_version. - // - // These are turbine generated jars so they only change if the externals of the - // class changes but it does not contain and implementation or JavaDoc. - SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths + // Map of sdk kind to the dex jar for the "everything" stubs. + // It is needed by the hiddenapi processing tool which processes dex files. + EverythingStubDexJarPaths map[android.SdkKind]OptionalDexJarPath - // SdkApiStubDexJar returns the dex jar for the stubs for the prebuilt - // java_sdk_library_import module. It is needed by the hiddenapi processing tool which - // processes dex files. - SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath + // Map of sdk kind to the dex jar for the "exportable" stubs. + // It is needed by the hiddenapi processing tool which processes dex files. + ExportableStubDexJarPaths map[android.SdkKind]OptionalDexJarPath - // SdkApiExportableStubDexJar returns the exportable dex jar for the stubs for - // java_sdk_library module. It is needed by the hiddenapi processing tool which processes - // dex files. - SdkApiExportableStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath + // Map of sdk kind to the optional path to the removed.txt file. + RemovedTxtFiles map[android.SdkKind]android.OptionalPath - // SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind. - SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath + // Whether if this can be used as a shared library. + SharedLibrary bool +} - // sharedLibrary returns true if this can be used as a shared library. - sharedLibrary() bool +var SdkLibraryInfoProvider = blueprint.NewProvider[SdkLibraryInfo]() - getImplLibraryModule() *Library +func getGeneratingLibs(ctx android.ModuleContext, sdkVersion android.SdkSpec, sdkLibraryModuleName string, sdkInfo SdkLibraryInfo) []string { + apiLevel := sdkVersion.ApiLevel + if apiLevel.IsPreview() { + return sdkInfo.GeneratingLibs + } + + generatingPrebuilts := []string{} + for _, apiScope := range AllApiScopes { + scopePrebuiltModuleName := prebuiltApiModuleName("sdk", sdkLibraryModuleName, apiScope.name, apiLevel.String()) + if ctx.OtherModuleExists(scopePrebuiltModuleName) { + generatingPrebuilts = append(generatingPrebuilts, scopePrebuiltModuleName) + } + } + return generatingPrebuilts } type SdkLibrary struct { @@ -1322,12 +1203,13 @@ type SdkLibrary struct { builtInstalledForApex []dexpreopterInstall } -var _ SdkLibraryDependency = (*SdkLibrary)(nil) - func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool { return module.sdkLibraryProperties.Generate_system_and_test_apis } +var _ UsesLibraryDependency = (*SdkLibrary)(nil) + +// To satisfy the UsesLibraryDependency interface func (module *SdkLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { if module.implLibraryModule != nil { return module.implLibraryModule.DexJarBuildPath(ctx) @@ -1335,6 +1217,7 @@ func (module *SdkLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) Optio return makeUnsetDexJarPath() } +// To satisfy the UsesLibraryDependency interface func (module *SdkLibrary) DexJarInstallPath() android.Path { if module.implLibraryModule != nil { return module.implLibraryModule.DexJarInstallPath() @@ -1397,7 +1280,7 @@ func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) { } func CheckMinSdkVersion(ctx android.ModuleContext, module *Library) { - android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.ModuleContext, do android.PayloadDepsCallback) { + android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.BaseModuleContext, do android.PayloadDepsCallback) { ctx.WalkDeps(func(child android.Module, parent android.Module) bool { isExternal := !module.depIsInSameApex(ctx, child) if am, ok := child.(android.ApexModule); ok { @@ -1452,7 +1335,7 @@ func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContex ctx.AddVariationDependencies(nil, apiScope.exportableStubsTag, exportableStubModuleName) // Add a dependency on the stubs source in order to access both stubs source and api information. - ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope)) + ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.droidstubsModuleName(apiScope)) if module.compareAgainstLatestApi(apiScope) { // Add dependencies on the latest finalized version of the API .txt file. @@ -1522,8 +1405,6 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) module.HideFromMake() } - module.generateCommonBuildActions(ctx) - module.stem = proptools.StringDefault(module.overridableProperties.Stem, ctx.ModuleName()) module.provideHiddenAPIPropertyInfo(ctx) @@ -1556,11 +1437,11 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) if dep, ok := android.OtherModuleProvider(ctx, to, JavaInfoProvider); ok { module.implLibraryHeaderJars = append(module.implLibraryHeaderJars, dep.HeaderJars...) module.implLibraryModule = to.(*Library) - android.SetProvider(ctx, JavaInfoProvider, dep) } } }) + sdkLibInfo := module.generateCommonBuildActions(ctx) apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) if !apexInfo.IsForPlatform() { module.hideApexVariantFromMake = true @@ -1589,7 +1470,10 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) module.dexer.proguardDictionary = module.implLibraryModule.dexer.proguardDictionary module.dexer.proguardUsageZip = module.implLibraryModule.dexer.proguardUsageZip module.linter.reports = module.implLibraryModule.linter.reports - module.linter.outputs.depSets = module.implLibraryModule.LintDepSets() + + if lintInfo, ok := android.OtherModuleProvider(ctx, module.implLibraryModule, LintProvider); ok { + android.SetProvider(ctx, LintProvider, lintInfo) + } if !module.Host() { module.hostdexInstallFile = module.implLibraryModule.hostdexInstallFile @@ -1631,9 +1515,21 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) } android.SetProvider(ctx, android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo}) module.setOutputFiles(ctx) + + var generatingLibs []string + for _, apiScope := range AllApiScopes { + if _, ok := module.scopePaths[apiScope]; ok { + generatingLibs = append(generatingLibs, module.stubsLibraryModuleName(apiScope)) + } + } + if module.requiresRuntimeImplementationLibrary() && module.implLibraryModule != nil { + generatingLibs = append(generatingLibs, module.implLibraryModuleName()) setOutputFiles(ctx, module.implLibraryModule.Module) } + + sdkLibInfo.GeneratingLibs = generatingLibs + android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo) } func (module *SdkLibrary) BuiltInstalledForApex() []dexpreopterInstall { @@ -1740,411 +1636,6 @@ func childModuleVisibility(childVisibility []string) []string { return visibility } -// Creates the implementation java library -func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) { - visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility) - - staticLibs := module.properties.Static_libs.Clone() - staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs) - props := struct { - Name *string - Visibility []string - Libs []string - Static_libs proptools.Configurable[[]string] - Apex_available []string - Stem *string - }{ - Name: proptools.StringPtr(module.implLibraryModuleName()), - Visibility: visibility, - - Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...), - - Static_libs: staticLibs, - // Pass the apex_available settings down so that the impl library can be statically - // embedded within a library that is added to an APEX. Needed for updatable-media. - Apex_available: module.ApexAvailable(), - - Stem: proptools.StringPtr(module.Name()), - } - - properties := []interface{}{ - &module.properties, - &module.protoProperties, - &module.deviceProperties, - &module.dexProperties, - &module.dexpreoptProperties, - &module.linter.properties, - &module.overridableProperties, - &props, - module.sdkComponentPropertiesForChildLibrary(), - } - mctx.CreateModule(LibraryFactory, properties...) -} - -type libraryProperties struct { - Name *string - Visibility []string - Srcs []string - Installable *bool - Sdk_version *string - System_modules *string - Patch_module *string - Libs []string - Static_libs []string - Compile_dex *bool - Java_version *string - Openjdk9 struct { - Srcs []string - Javacflags []string - } - Dist struct { - Targets []string - Dest *string - Dir *string - Tag *string - } - Is_stubs_module *bool - Stub_contributing_api *string -} - -func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties { - props := libraryProperties{} - props.Visibility = []string{"//visibility:override", "//visibility:private"} - // sources are generated from the droiddoc - sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) - props.Sdk_version = proptools.StringPtr(sdkVersion) - props.System_modules = module.deviceProperties.System_modules - props.Patch_module = module.properties.Patch_module - props.Installable = proptools.BoolPtr(false) - props.Libs = module.sdkLibraryProperties.Stub_only_libs - props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...) - props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs - // The stub-annotations library contains special versions of the annotations - // with CLASS retention policy, so that they're kept. - if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) { - props.Libs = append(props.Libs, "stub-annotations") - } - props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs - props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags - // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential - // interop with older developer tools that don't support 1.9. - props.Java_version = proptools.StringPtr("1.8") - props.Is_stubs_module = proptools.BoolPtr(true) - props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String()) - - return props -} - -// Creates a static java library that has API stubs -func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { - - props := module.stubsLibraryProps(mctx, apiScope) - props.Name = proptools.StringPtr(module.sourceStubsLibraryModuleName(apiScope)) - props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)} - - mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) -} - -// Create a static java library that compiles the "exportable" stubs -func (module *SdkLibrary) createExportableStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { - props := module.stubsLibraryProps(mctx, apiScope) - props.Name = proptools.StringPtr(module.exportableSourceStubsLibraryModuleName(apiScope)) - props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope) + "{.exportable}"} - - mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) -} - -// Creates a droidstubs module that creates stubs source files from the given full source -// files and also updates and checks the API specification files. -func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) { - props := struct { - Name *string - Visibility []string - Srcs []string - Installable *bool - Sdk_version *string - Api_surface *string - System_modules *string - Libs proptools.Configurable[[]string] - Output_javadoc_comments *bool - Arg_files []string - Args *string - Java_version *string - Annotations_enabled *bool - Merge_annotations_dirs []string - Merge_inclusion_annotations_dirs []string - Generate_stubs *bool - Previous_api *string - Aconfig_declarations []string - Check_api struct { - Current ApiToCheck - Last_released ApiToCheck - - Api_lint struct { - Enabled *bool - New_since *string - Baseline_file *string - } - } - Aidl struct { - Include_dirs []string - Local_include_dirs []string - } - Dists []android.Dist - }{} - - // The stubs source processing uses the same compile time classpath when extracting the - // API from the implementation library as it does when compiling it. i.e. the same - // * sdk version - // * system_modules - // * libs (static_libs/libs) - - props.Name = proptools.StringPtr(name) - props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility) - props.Srcs = append(props.Srcs, module.properties.Srcs...) - props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...) - props.Sdk_version = module.deviceProperties.Sdk_version - props.Api_surface = &apiScope.name - props.System_modules = module.deviceProperties.System_modules - props.Installable = proptools.BoolPtr(false) - // A droiddoc module has only one Libs property and doesn't distinguish between - // shared libs and static libs. So we need to add both of these libs to Libs property. - props.Libs = proptools.NewConfigurable[[]string](nil, nil) - props.Libs.AppendSimpleValue(module.properties.Libs) - props.Libs.Append(module.properties.Static_libs) - props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs) - props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs) - props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs - props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs - props.Java_version = module.properties.Java_version - - props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled - props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs - props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs - props.Aconfig_declarations = module.sdkLibraryProperties.Aconfig_declarations - - droidstubsArgs := []string{} - if len(module.sdkLibraryProperties.Api_packages) != 0 { - droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":")) - } - droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...) - disabledWarnings := []string{"HiddenSuperclass"} - if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) { - disabledWarnings = append(disabledWarnings, - "BroadcastBehavior", - "DeprecationMismatch", - "MissingPermission", - "SdkConstant", - "Todo", - ) - } - droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide ")) - - // Output Javadoc comments for public scope. - if apiScope == apiScopePublic { - props.Output_javadoc_comments = proptools.BoolPtr(true) - } - - // Add in scope specific arguments. - droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...) - props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files - props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " ")) - - // List of APIs identified from the provided source files are created. They are later - // compared against to the not-yet-released (a.k.a current) list of APIs and to the - // last-released (a.k.a numbered) list of API. - currentApiFileName := apiScope.apiFilePrefix + "current.txt" - removedApiFileName := apiScope.apiFilePrefix + "removed.txt" - apiDir := module.getApiDir() - currentApiFileName = path.Join(apiDir, currentApiFileName) - removedApiFileName = path.Join(apiDir, removedApiFileName) - - // check against the not-yet-release API - props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName) - props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName) - - if module.compareAgainstLatestApi(apiScope) { - // check against the latest released API - latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) - props.Previous_api = latestApiFilegroupName - props.Check_api.Last_released.Api_file = latestApiFilegroupName - props.Check_api.Last_released.Removed_api_file = proptools.StringPtr( - module.latestRemovedApiFilegroupName(apiScope)) - props.Check_api.Last_released.Baseline_file = proptools.StringPtr( - module.latestIncompatibilitiesFilegroupName(apiScope)) - - if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) { - // Enable api lint. - props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true) - props.Check_api.Api_lint.New_since = latestApiFilegroupName - - // If it exists then pass a lint-baseline.txt through to droidstubs. - baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt") - baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath) - paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil) - if err != nil { - mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err) - } - if len(paths) == 1 { - props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath) - } else if len(paths) != 0 { - mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths) - } - } - } - - if !Bool(module.sdkLibraryProperties.No_dist) { - // Dist the api txt and removed api txt artifacts for sdk builds. - distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api")) - stubsTypeTagPrefix := "" - if mctx.Config().ReleaseHiddenApiExportableStubs() { - stubsTypeTagPrefix = ".exportable" - } - for _, p := range []struct { - tag string - pattern string - }{ - // "exportable" api files are copied to the dist directory instead of the - // "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag - // is set. Otherwise, the "everything" api files are copied to the dist directory. - {tag: "%s.api.txt", pattern: "%s.txt"}, - {tag: "%s.removed-api.txt", pattern: "%s-removed.txt"}, - } { - props.Dists = append(props.Dists, android.Dist{ - Targets: []string{"sdk", "win_sdk"}, - Dir: distDir, - Dest: proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())), - Tag: proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)), - }) - } - } - - mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx) -} - -func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { - props := struct { - Name *string - Visibility []string - Api_contributions []string - Libs proptools.Configurable[[]string] - Static_libs []string - System_modules *string - Enable_validation *bool - Stubs_type *string - Sdk_version *string - Previous_api *string - }{} - - props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope)) - props.Visibility = []string{"//visibility:override", "//visibility:private"} - - apiContributions := []string{} - - // Api surfaces are not independent of each other, but have subset relationships, - // and so does the api files. To generate from-text stubs for api surfaces other than public, - // all subset api domains' api_contriubtions must be added as well. - scope := apiScope - for scope != nil { - apiContributions = append(apiContributions, module.stubsSourceModuleName(scope)+".api.contribution") - scope = scope.extends - } - if apiScope == apiScopePublic { - additionalApiContribution := module.apiLibraryAdditionalApiContribution() - if additionalApiContribution != "" { - apiContributions = append(apiContributions, additionalApiContribution) - } - } - - props.Api_contributions = apiContributions - - // Ensure that stub-annotations is added to the classpath before any other libs - props.Libs = proptools.NewConfigurable[[]string](nil, nil) - props.Libs.AppendSimpleValue([]string{"stub-annotations"}) - props.Libs.AppendSimpleValue(module.properties.Libs) - props.Libs.Append(module.properties.Static_libs) - props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs) - props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs) - props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs - - props.System_modules = module.deviceProperties.System_modules - props.Enable_validation = proptools.BoolPtr(true) - props.Stubs_type = proptools.StringPtr("everything") - - if module.deviceProperties.Sdk_version != nil { - props.Sdk_version = module.deviceProperties.Sdk_version - } - - if module.compareAgainstLatestApi(apiScope) { - // check against the latest released API - latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) - props.Previous_api = latestApiFilegroupName - } - - mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) -} - -func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties { - props := libraryProperties{} - - props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) - sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) - props.Sdk_version = proptools.StringPtr(sdkVersion) - - props.System_modules = module.deviceProperties.System_modules - - // The imports need to be compiled to dex if the java_sdk_library requests it. - compileDex := module.dexProperties.Compile_dex - if module.stubLibrariesCompiledForDex() { - compileDex = proptools.BoolPtr(true) - } - props.Compile_dex = compileDex - - props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String()) - - if !Bool(module.sdkLibraryProperties.No_dist) && doDist { - props.Dist.Targets = []string{"sdk", "win_sdk"} - props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem())) - props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope)) - props.Dist.Tag = proptools.StringPtr(".jar") - } - props.Is_stubs_module = proptools.BoolPtr(true) - - return props -} - -func (module *SdkLibrary) createTopLevelStubsLibrary( - mctx android.DefaultableHookContext, apiScope *apiScope) { - - // Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false - doDist := !mctx.Config().ReleaseHiddenApiExportableStubs() - props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist) - props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) - - // Add the stub compiling java_library/java_api_library as static lib based on build config - staticLib := module.sourceStubsLibraryModuleName(apiScope) - if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() { - staticLib = module.apiLibraryModuleName(apiScope) - } - props.Static_libs = append(props.Static_libs, staticLib) - - mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) -} - -func (module *SdkLibrary) createTopLevelExportableStubsLibrary( - mctx android.DefaultableHookContext, apiScope *apiScope) { - - // Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true - doDist := mctx.Config().ReleaseHiddenApiExportableStubs() - props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist) - props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope)) - - staticLib := module.exportableSourceStubsLibraryModuleName(apiScope) - props.Static_libs = append(props.Static_libs, staticLib) - - mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) -} - func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool { return !(apiScope.unstable || module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api) } @@ -2170,104 +1661,6 @@ func (module *SdkLibrary) ModuleBuildFromTextStubs() bool { return proptools.BoolDefault(module.sdkLibraryProperties.Build_from_text_stub, true) } -// Creates the xml file that publicizes the runtime library -func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { - moduleMinApiLevel := module.Library.MinSdkVersion(mctx) - var moduleMinApiLevelStr = moduleMinApiLevel.String() - if moduleMinApiLevel == android.NoneApiLevel { - moduleMinApiLevelStr = "current" - } - props := struct { - Name *string - Lib_name *string - Apex_available []string - On_bootclasspath_since *string - On_bootclasspath_before *string - Min_device_sdk *string - Max_device_sdk *string - Sdk_library_min_api_level *string - Uses_libs_dependencies []string - }{ - Name: proptools.StringPtr(module.xmlPermissionsModuleName()), - Lib_name: proptools.StringPtr(module.BaseModuleName()), - Apex_available: module.ApexProperties.Apex_available, - On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since, - On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before, - Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk, - Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk, - Sdk_library_min_api_level: &moduleMinApiLevelStr, - Uses_libs_dependencies: module.usesLibraryProperties.Uses_libs, - } - - mctx.CreateModule(sdkLibraryXmlFactory, &props) -} - -func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s android.SdkSpec) android.Paths { - var ver android.ApiLevel - var kind android.SdkKind - if s.UsePrebuilt(ctx) { - ver = s.ApiLevel - kind = s.Kind - } else { - // We don't have prebuilt SDK for the specific sdkVersion. - // Instead of breaking the build, fallback to use "system_current" - ver = android.FutureApiLevel - kind = android.SdkSystem - } - - dir := filepath.Join("prebuilts", "sdk", ver.String(), kind.String()) - jar := filepath.Join(dir, baseName+".jar") - jarPath := android.ExistentPathForSource(ctx, jar) - if !jarPath.Valid() { - if ctx.Config().AllowMissingDependencies() { - return android.Paths{android.PathForSource(ctx, jar)} - } else { - ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", s.Raw, jar) - } - return nil - } - return android.Paths{jarPath.Path()} -} - -// Check to see if the other module is within the same set of named APEXes as this module. -// -// If either this or the other module are on the platform then this will return -// false. -func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool { - apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) - otherApexInfo, _ := android.OtherModuleProvider(ctx, other, android.ApexInfoProvider) - return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants) -} - -func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { - // If the client doesn't set sdk_version, but if this library prefers stubs over - // the impl library, let's provide the widest API surface possible. To do so, - // force override sdk_version to module_current so that the closest possible API - // surface could be found in selectHeaderJarsForSdkVersion - if module.defaultsToStubs() && !sdkVersion.Specified() { - sdkVersion = android.SdkSpecFrom(ctx, "module_current") - } - - // Only provide access to the implementation library if it is actually built. - if module.requiresRuntimeImplementationLibrary() { - // Check any special cases for java_sdk_library. - // - // Only allow access to the implementation library in the following condition: - // * No sdk_version specified on the referencing module. - // * The referencing module is in the same apex as this. - if sdkVersion.Kind == android.SdkPrivate || withinSameApexesAs(ctx, module) { - return module.implLibraryHeaderJars - } - } - - return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion) -} - -// to satisfy SdkLibraryDependency interface -func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { - return module.sdkJars(ctx, sdkVersion) -} - var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries") func javaSdkLibraries(config android.Config) *[]string { @@ -2284,11 +1677,6 @@ func (module *SdkLibrary) getApiDir() string { // runtime libs and xml file. If requested, the stubs and docs are created twice // once for public API level and once for system API level func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookContext) { - // If the module has been disabled then don't create any child modules. - if !module.Enabled(mctx) { - return - } - if len(module.properties.Srcs) == 0 { mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs") return @@ -2338,10 +1726,10 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont for _, scope := range generatedScopes { // Use the stubs source name for legacy reasons. - module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs) + module.createDroidstubs(mctx, scope, module.droidstubsModuleName(scope), scope.droidstubsArgs) - module.createStubsLibrary(mctx, scope) - module.createExportableStubsLibrary(mctx, scope) + module.createFromSourceStubsLibrary(mctx, scope) + module.createExportableFromSourceStubsLibrary(mctx, scope) if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() { module.createApiLibrary(mctx, scope) @@ -2391,54 +1779,6 @@ func (module *SdkLibrary) requiresRuntimeImplementationLibrary() bool { return !proptools.Bool(module.sdkLibraryProperties.Api_only) } -func (module *SdkLibrary) defaultsToStubs() bool { - return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs) -} - -// Defines how to name the individual component modules the sdk library creates. -type sdkLibraryComponentNamingScheme interface { - stubsLibraryModuleName(scope *apiScope, baseName string) string - - stubsSourceModuleName(scope *apiScope, baseName string) string - - apiLibraryModuleName(scope *apiScope, baseName string) string - - sourceStubsLibraryModuleName(scope *apiScope, baseName string) string - - exportableStubsLibraryModuleName(scope *apiScope, baseName string) string - - exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string -} - -type defaultNamingScheme struct { -} - -func (s *defaultNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string { - return scope.stubsLibraryModuleName(baseName) -} - -func (s *defaultNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string { - return scope.stubsSourceModuleName(baseName) -} - -func (s *defaultNamingScheme) apiLibraryModuleName(scope *apiScope, baseName string) string { - return scope.apiLibraryModuleName(baseName) -} - -func (s *defaultNamingScheme) sourceStubsLibraryModuleName(scope *apiScope, baseName string) string { - return scope.sourceStubLibraryModuleName(baseName) -} - -func (s *defaultNamingScheme) exportableStubsLibraryModuleName(scope *apiScope, baseName string) string { - return scope.exportableStubsLibraryModuleName(baseName) -} - -func (s *defaultNamingScheme) exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string { - return scope.exportableSourceStubsLibraryModuleName(baseName) -} - -var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil) - func moduleStubLinkType(j *Module) (stub bool, ret sdkLinkType) { kind := android.ToSdkKind(proptools.String(j.properties.Stub_contributing_api)) switch kind { @@ -2500,7 +1840,7 @@ func SdkLibraryFactory() android.Module { module.commonSdkLibraryProperties.Shared_library = proptools.BoolPtr(false) } - if module.initCommonAfterDefaultsApplied(ctx) { + if module.initCommonAfterDefaultsApplied() { module.CreateInternalModules(ctx) } }) @@ -2579,8 +1919,6 @@ type SdkLibraryImport struct { installFile android.Path } -var _ SdkLibraryDependency = (*SdkLibraryImport)(nil) - // The type of a structure that contains a field of type sdkLibraryScopeProperties // for each apiscope in allApiScopes, e.g. something like: // @@ -2636,7 +1974,7 @@ func sdkLibraryImportFactory() android.Module { InitJavaModule(module, android.HostAndDeviceSupported) module.SetDefaultableHook(func(mctx android.DefaultableHookContext) { - if module.initCommonAfterDefaultsApplied(mctx) { + if module.initCommonAfterDefaultsApplied() { module.createInternalModules(mctx) } }) @@ -2690,86 +2028,6 @@ func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHo *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName()) } -func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { - // Creates a java import for the jar with ".stubs" suffix - props := struct { - Name *string - Source_module_name *string - Created_by_java_sdk_library_name *string - Sdk_version *string - Libs []string - Jars []string - Compile_dex *bool - Is_stubs_module *bool - - android.UserSuppliedPrebuiltProperties - }{} - props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) - props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName())) - props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) - props.Sdk_version = scopeProperties.Sdk_version - // Prepend any of the libs from the legacy public properties to the libs for each of the - // scopes to avoid having to duplicate them in each scope. - props.Libs = append(module.properties.Libs, scopeProperties.Libs...) - props.Jars = scopeProperties.Jars - - // The imports are preferred if the java_sdk_library_import is preferred. - props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) - - // The imports need to be compiled to dex if the java_sdk_library_import requests it. - compileDex := module.properties.Compile_dex - if module.stubLibrariesCompiledForDex() { - compileDex = proptools.BoolPtr(true) - } - props.Compile_dex = compileDex - props.Is_stubs_module = proptools.BoolPtr(true) - - mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) -} - -func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { - props := struct { - Name *string - Source_module_name *string - Created_by_java_sdk_library_name *string - Srcs []string - - android.UserSuppliedPrebuiltProperties - }{} - props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope)) - props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName())) - props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) - props.Srcs = scopeProperties.Stub_srcs - - // The stubs source is preferred if the java_sdk_library_import is preferred. - props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) - - mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary()) -} - -func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { - api_file := scopeProperties.Current_api - api_surface := &apiScope.name - - props := struct { - Name *string - Source_module_name *string - Created_by_java_sdk_library_name *string - Api_surface *string - Api_file *string - Visibility []string - }{} - - props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope) + ".api.contribution") - props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution") - props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) - props.Api_surface = api_surface - props.Api_file = api_file - props.Visibility = []string{"//visibility:override", "//visibility:public"} - - mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) -} - // Add the dependencies on the child module in the component deps mutator so that it // creates references to the prebuilt and not the source modules. func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { @@ -2783,7 +2041,7 @@ func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutator if len(scopeProperties.Stub_srcs) > 0 { // Add dependencies to the prebuilt stubs source library - ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, android.PrebuiltNameFromSource(module.stubsSourceModuleName(apiScope))) + ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, android.PrebuiltNameFromSource(module.droidstubsModuleName(apiScope))) } } } @@ -2837,8 +2095,6 @@ func (module *SdkLibraryImport) MinSdkVersion(ctx android.EarlyModuleContext) an var _ hiddenAPIModule = (*SdkLibraryImport)(nil) func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { - module.generateCommonBuildActions(ctx) - // Assume that source module(sdk_library) is installed in /<sdk_library partition>/framework module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar") @@ -2868,6 +2124,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo } } }) + sdkLibInfo := module.generateCommonBuildActions(ctx) // Populate the scope paths with information from the properties. for apiScope, scopeProperties := range module.scopeProperties { @@ -2882,70 +2139,38 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo } if ctx.Device() { - // If this is a variant created for a prebuilt_apex then use the dex implementation jar - // obtained from the associated deapexer module. + // Shared libraries deapexed from prebuilt apexes are no longer supported. + // Set the dexJarBuildPath to a fake path. + // This allows soong analysis pass, but will be an error during ninja execution if there are + // any rdeps. ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) if ai.ForPrebuiltApex { - // Get the path of the dex implementation jar from the `deapexer` module. - di, err := android.FindDeapexerProviderForModule(ctx) - if err != nil { - // An error was found, possibly due to multiple apexes in the tree that export this library - // Defer the error till a client tries to call DexJarBuildPath - module.dexJarFileErr = err - module.initHiddenAPIError(err) - return - } - dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(module.BaseModuleName()) - if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil { - dexJarFile := makeDexJarPathFromPath(dexOutputPath) - module.dexJarFile = dexJarFile - installPath := android.PathForModuleInPartitionInstall( - ctx, "apex", ai.ApexVariationName, dexJarFileApexRootRelative) - module.installFile = installPath - module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil) - - module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath) - module.dexpreopter.isSDKLibrary = true - module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &module.dexpreopter) - - if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil { - module.dexpreopter.inputProfilePathOnHost = profilePath - } - } else { - // This should never happen as a variant for a prebuilt_apex is only created if the - // prebuilt_apex has been configured to export the java library dex file. - ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt APEX %s", di.ApexModuleName()) + module.dexJarFile = makeDexJarPathFromPath(android.PathForModuleInstall(ctx, "intentionally_no_longer_supported")) + module.initHiddenAPI(ctx, module.dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil) + } + } + + var generatingLibs []string + for _, apiScope := range AllApiScopes { + if scopeProperties, ok := module.scopeProperties[apiScope]; ok { + if len(scopeProperties.Jars) == 0 { + continue } + generatingLibs = append(generatingLibs, module.stubsLibraryModuleName(apiScope)) } } module.setOutputFiles(ctx) if module.implLibraryModule != nil { + generatingLibs = append(generatingLibs, module.implLibraryModuleName()) setOutputFiles(ctx, module.implLibraryModule.Module) } -} - -func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths { - // For consistency with SdkLibrary make the implementation jar available to libraries that - // are within the same APEX. - implLibraryModule := module.implLibraryModule - if implLibraryModule != nil && withinSameApexesAs(ctx, module) { - if headerJars { - return implLibraryModule.HeaderJars() - } else { - return implLibraryModule.ImplementationJars() - } - } - - return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion) + sdkLibInfo.GeneratingLibs = generatingLibs + android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo) } -// to satisfy SdkLibraryDependency interface -func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { - // This module is just a wrapper for the prebuilt stubs. - return module.sdkJars(ctx, sdkVersion, true) -} +var _ UsesLibraryDependency = (*SdkLibraryImport)(nil) // to satisfy UsesLibraryDependency interface func (module *SdkLibraryImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { @@ -2984,29 +2209,6 @@ func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { } // to satisfy apex.javaDependency interface -func (module *SdkLibraryImport) LintDepSets() LintDepSets { - if module.implLibraryModule == nil { - return LintDepSets{} - } else { - return module.implLibraryModule.LintDepSets() - } -} - -func (module *SdkLibraryImport) GetStrictUpdatabilityLinting() bool { - if module.implLibraryModule == nil { - return false - } else { - return module.implLibraryModule.GetStrictUpdatabilityLinting() - } -} - -func (module *SdkLibraryImport) SetStrictUpdatabilityLinting(strictLinting bool) { - if module.implLibraryModule != nil { - module.implLibraryModule.SetStrictUpdatabilityLinting(strictLinting) - } -} - -// to satisfy apex.javaDependency interface func (module *SdkLibraryImport) Stem() string { return module.BaseModuleName() } @@ -3047,333 +2249,6 @@ func (j *SdkLibraryImport) UseProfileGuidedDexpreopt() bool { return proptools.Bool(j.importDexpreoptProperties.Dex_preopt.Profile_guided) } -// java_sdk_library_xml -type sdkLibraryXml struct { - android.ModuleBase - android.DefaultableModuleBase - android.ApexModuleBase - - properties sdkLibraryXmlProperties - - outputFilePath android.OutputPath - installDirPath android.InstallPath - - hideApexVariantFromMake bool -} - -type sdkLibraryXmlProperties struct { - // canonical name of the lib - Lib_name *string - - // Signals that this shared library is part of the bootclasspath starting - // on the version indicated in this attribute. - // - // This will make platforms at this level and above to ignore - // <uses-library> tags with this library name because the library is already - // available - On_bootclasspath_since *string - - // Signals that this shared library was part of the bootclasspath before - // (but not including) the version indicated in this attribute. - // - // The system will automatically add a <uses-library> tag with this library to - // apps that target any SDK less than the version indicated in this attribute. - On_bootclasspath_before *string - - // Indicates that PackageManager should ignore this shared library if the - // platform is below the version indicated in this attribute. - // - // This means that the device won't recognise this library as installed. - Min_device_sdk *string - - // Indicates that PackageManager should ignore this shared library if the - // platform is above the version indicated in this attribute. - // - // This means that the device won't recognise this library as installed. - Max_device_sdk *string - - // The SdkLibrary's min api level as a string - // - // This value comes from the ApiLevel of the MinSdkVersion property. - Sdk_library_min_api_level *string - - // Uses-libs dependencies that the shared library requires to work correctly. - // - // This will add dependency="foo:bar" to the <library> section. - Uses_libs_dependencies []string -} - -// java_sdk_library_xml builds the permission xml file for a java_sdk_library. -// Not to be used directly by users. java_sdk_library internally uses this. -func sdkLibraryXmlFactory() android.Module { - module := &sdkLibraryXml{} - - module.AddProperties(&module.properties) - - android.InitApexModule(module) - android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) - - return module -} - -func (module *sdkLibraryXml) UniqueApexVariations() bool { - // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the - // mounted APEX, which contains the name of the APEX. - return true -} - -// from android.PrebuiltEtcModule -func (module *sdkLibraryXml) BaseDir() string { - return "etc" -} - -// from android.PrebuiltEtcModule -func (module *sdkLibraryXml) SubDir() string { - return "permissions" -} - -var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil) - -// from android.ApexModule -func (module *sdkLibraryXml) AvailableFor(what string) bool { - return true -} - -func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { - // do nothing -} - -var _ android.ApexModule = (*sdkLibraryXml)(nil) - -// Implements android.ApexModule -func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { - // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked - return nil -} - -// File path to the runtime implementation library -func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string { - implName := proptools.String(module.properties.Lib_name) - if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() { - // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name. - // In most cases, this works fine. But when apex_name is set or override_apex is used - // this can be wrong. - return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.BaseApexName, implName) - } - partition := "system" - if module.SocSpecific() { - partition = "vendor" - } else if module.DeviceSpecific() { - partition = "odm" - } else if module.ProductSpecific() { - partition = "product" - } else if module.SystemExtSpecific() { - partition = "system_ext" - } - return "/" + partition + "/framework/" + implName + ".jar" -} - -func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string { - if value == nil { - return "" - } - apiLevel, err := android.ApiLevelFromUser(ctx, *value) - if err != nil { - // attributes in bp files have underscores but in the xml have dashes. - ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error()) - return "" - } - if apiLevel.IsCurrent() { - // passing "current" would always mean a future release, never the current (or the current in - // progress) which means some conditions would never be triggered. - ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), - `"current" is not an allowed value for this attribute`) - return "" - } - // "safeValue" is safe because it translates finalized codenames to a string - // with their SDK int. - safeValue := apiLevel.String() - return formattedOptionalAttribute(attrName, &safeValue) -} - -// formats an attribute for the xml permissions file if the value is not null -// returns empty string otherwise -func formattedOptionalAttribute(attrName string, value *string) string { - if value == nil { - return "" - } - 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, ":")) -} - -func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string { - libName := proptools.String(module.properties.Lib_name) - libNameAttr := formattedOptionalAttribute("name", &libName) - filePath := module.implPath(ctx) - filePathAttr := formattedOptionalAttribute("file", &filePath) - implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since) - implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before) - minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk) - maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk) - dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies) - // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that). - // 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" - } else { - 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", - libraryTag, - libNameAttr, - filePathAttr, - implicitFromAttr, - implicitUntilAttr, - minSdkAttr, - maxSdkAttr, - dependenciesAttr, - " />\n", - "</permissions>\n", - }, "") -} - -func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) { - apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) - module.hideApexVariantFromMake = !apexInfo.IsForPlatform() - - libName := proptools.String(module.properties.Lib_name) - module.selfValidate(ctx) - xmlContent := module.permissionsContents(ctx) - - module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath - android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent) - - module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir()) - ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath) - - ctx.SetOutputFiles(android.OutputPaths{module.outputFilePath}.Paths(), "") -} - -func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries { - if module.hideApexVariantFromMake { - return []android.AndroidMkEntries{{ - Disabled: true, - }} - } - - return []android.AndroidMkEntries{{ - Class: "ETC", - OutputFile: android.OptionalPathForPath(module.outputFilePath), - ExtraEntries: []android.AndroidMkExtraEntriesFunc{ - func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_MODULE_TAGS", "optional") - entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String()) - entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base()) - }, - }, - }} -} - -func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) { - module.validateAtLeastTAttributes(ctx) - module.validateMinAndMaxDeviceSdk(ctx) - module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx) - module.validateOnBootclasspathBeforeRequirements(ctx) -} - -func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) { - t := android.ApiLevelOrPanic(ctx, "Tiramisu") - module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk") - module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk") - module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before") - module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since") -} - -func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) { - if attr != nil { - if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil { - // we will inform the user of invalid inputs when we try to write the - // permissions xml file so we don't need to do it here - if t.GreaterThan(level) { - ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T") - } - } - } -} - -func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) { - if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil { - min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) - max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) - if minErr == nil && maxErr == nil { - // we will inform the user of invalid inputs when we try to write the - // permissions xml file so we don't need to do it here - if min.GreaterThan(max) { - ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk") - } - } - } -} - -func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) { - moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) - if module.properties.Min_device_sdk != nil { - api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) - if err == nil { - if moduleMinApi.GreaterThan(api) { - ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) - } - } - } - if module.properties.Max_device_sdk != nil { - api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) - if err == nil { - if moduleMinApi.GreaterThan(api) { - ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) - } - } - } -} - -func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) { - moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) - if module.properties.On_bootclasspath_before != nil { - t := android.ApiLevelOrPanic(ctx, "Tiramisu") - // if we use the attribute, then we need to do this validation - if moduleMinApi.LessThan(t) { - // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+) - if module.properties.Min_device_sdk == nil { - ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T") - } - } - } -} - type sdkLibrarySdkMemberType struct { android.SdkMemberTypeBase } @@ -3510,7 +2385,6 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe } } - 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 @@ -3520,7 +2394,7 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk - implLibrary := sdk.getImplLibraryModule() + implLibrary := sdk.implLibraryModule if implLibrary != nil && implLibrary.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided { s.DexPreoptProfileGuided = proptools.BoolPtr(true) } diff --git a/java/sdk_library_external.go b/java/sdk_library_external.go deleted file mode 100644 index 4f8398194..000000000 --- a/java/sdk_library_external.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2020 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package java - -import ( - "android/soong/android" -) - -type partitionGroup int - -// Representation of partition group for checking inter-partition library dependencies. -// Between system and system_ext, there are no restrictions of dependencies, -// so we can treat these partitions as the same in terms of inter-partition dependency. -// Same policy is applied between vendor and odm partiton. -const ( - partitionGroupNone partitionGroup = iota - // group for system, and system_ext partition - partitionGroupSystem - // group for vendor and odm partition - partitionGroupVendor - // product partition - partitionGroupProduct -) - -func (g partitionGroup) String() string { - switch g { - case partitionGroupSystem: - return "system" - case partitionGroupVendor: - return "vendor" - case partitionGroupProduct: - return "product" - } - - return "" -} - -// Get partition group of java module that can be used at inter-partition dependency check. -// We currently have three groups -// -// (system, system_ext) => system partition group -// (vendor, odm) => vendor partition group -// (product) => product partition group -func (j *Module) partitionGroup(ctx android.EarlyModuleContext) partitionGroup { - // system and system_ext partition can be treated as the same in terms of inter-partition dependency. - if j.Platform() || j.SystemExtSpecific() { - return partitionGroupSystem - } - - // vendor and odm partition can be treated as the same in terms of inter-partition dependency. - if j.SocSpecific() || j.DeviceSpecific() { - return partitionGroupVendor - } - - // product partition is independent. - if j.ProductSpecific() { - return partitionGroupProduct - } - - panic("Cannot determine partition type") -} - -func (j *Module) allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool { - return inList(j.Name(), ctx.Config().InterPartitionJavaLibraryAllowList()) -} - -func (j *Module) syspropWithPublicStubs() bool { - return j.deviceProperties.SyspropPublicStub != "" -} - -type javaSdkLibraryEnforceContext interface { - Name() string - allowListedInterPartitionJavaLibrary(ctx android.EarlyModuleContext) bool - partitionGroup(ctx android.EarlyModuleContext) partitionGroup - syspropWithPublicStubs() bool -} - -var _ javaSdkLibraryEnforceContext = (*Module)(nil) - -func (j *Module) checkPartitionsForJavaDependency(ctx android.EarlyModuleContext, propName string, dep javaSdkLibraryEnforceContext) { - if dep.allowListedInterPartitionJavaLibrary(ctx) { - return - } - - if dep.syspropWithPublicStubs() { - return - } - - // If product interface is not enforced, skip check between system and product partition. - // But still need to check between product and vendor partition because product interface flag - // just represents enforcement between product and system, and vendor interface enforcement - // that is enforced here by precondition is representing enforcement between vendor and other partitions. - if !ctx.Config().EnforceProductPartitionInterface() { - productToSystem := j.partitionGroup(ctx) == partitionGroupProduct && dep.partitionGroup(ctx) == partitionGroupSystem - systemToProduct := j.partitionGroup(ctx) == partitionGroupSystem && dep.partitionGroup(ctx) == partitionGroupProduct - - if productToSystem || systemToProduct { - return - } - } - - // If module and dependency library is inter-partition - if j.partitionGroup(ctx) != dep.partitionGroup(ctx) { - errorFormat := "dependency on java_library (%q) is not allowed across the partitions (%s -> %s), use java_sdk_library instead" - ctx.PropertyErrorf(propName, errorFormat, dep.Name(), j.partitionGroup(ctx), dep.partitionGroup(ctx)) - } -} diff --git a/java/sdk_library_internal.go b/java/sdk_library_internal.go new file mode 100644 index 000000000..ca088cf68 --- /dev/null +++ b/java/sdk_library_internal.go @@ -0,0 +1,1017 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "android/soong/android" + "android/soong/etc" + "fmt" + "path" + "strings" + + "github.com/google/blueprint/proptools" +) + +// --------------------------------------------------------------------------------------------- +// Naming scheme of the submodules generated by java_sdk_library and java_sdk_library_import +// --------------------------------------------------------------------------------------------- + +const ( + sdkXmlFileSuffix = ".xml" + implLibSuffix = ".impl" +) + +func implLibraryModuleName(sdkLibName string) string { + return sdkLibName + implLibSuffix +} + +// Module name of the runtime implementation library +func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string { + return implLibraryModuleName(c.module.RootLibraryName()) +} + +// Module name of the XML file for the lib +func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string { + return c.module.RootLibraryName() + sdkXmlFileSuffix +} + +// Name of the java_library module that compiles the stubs source. +func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string { + baseName := c.module.RootLibraryName() + return apiScope.stubsLibraryModuleName(baseName) +} + +// Name of the java_library module that compiles the exportable stubs source. +func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string { + baseName := c.module.RootLibraryName() + return apiScope.exportableStubsLibraryModuleName(baseName) +} + +// Name of the droidstubs module that generates the stubs source and may also +// generate/check the API. +func (c *commonToSdkLibraryAndImport) droidstubsModuleName(apiScope *apiScope) string { + baseName := c.module.RootLibraryName() + return apiScope.stubsSourceModuleName(baseName) +} + +// Name of the java_api_library module that generates the from-text stubs source +// and compiles to a jar file. +func (c *commonToSdkLibraryAndImport) fromTextStubsLibraryModuleName(apiScope *apiScope) string { + baseName := c.module.RootLibraryName() + return apiScope.apiLibraryModuleName(baseName) +} + +// Name of the java_library module that compiles the stubs +// generated from source Java files. +func (c *commonToSdkLibraryAndImport) fromSourceStubsLibraryModuleName(apiScope *apiScope) string { + baseName := c.module.RootLibraryName() + return apiScope.sourceStubsLibraryModuleName(baseName) +} + +// Name of the java_library module that compiles the exportable stubs +// generated from source Java files. +func (c *commonToSdkLibraryAndImport) exportableFromSourceStubsLibraryModuleName(apiScope *apiScope) string { + baseName := c.module.RootLibraryName() + return apiScope.exportableSourceStubsLibraryModuleName(baseName) +} + +// --------------------------------------------------------------------------------------------- +// Build rules of the submodules generated by java_sdk_library. +// java_sdk_library "framework-foo" generates the following submodules: +// +// - "framework-foo.impl" (type: [Library]): the implementation library, which generates the +// compilation outputs that include the implementation details and the private apis +// (i.e. class/methods that are annotated @hide). +// +// - "framework-foo.stubs.source.<[apiScope.name]>" (type: [Droidstubs]): droidstubs module that +// generates the stubs and the api files for the given api scope. +// +// - "framework-foo.stubs.<[apiScope.name]>" (type: [Library]): stub library module that +// provides the compilation output of the stubs to the reverse dependencies. The module +// itself does not perform any compilation actions; the module statically depends on one of +// the from-source stub module or the from-text stub configuration based on the build +// configuration. +// +// - "framework-foo.stubs.<[apiScope.name]>.from-source" (type: [Library]): stub library module +// that compiles the stubs generated by the droidstubs submodule. This module is a static +// dependency of the stub library module when +// [android/soong/android/config.BuildFromTextStub()] is false. +// +// - "framework-foo.stubs.<[apiScope.name]>.from-text" (type: [ApiLibrary]): api library module +// that generates and compiles the stubs from the api files checked in the tree instead of +// the source Java files (e.g. *-current.txt files). This module is a static dependency of +// the stub library module when [android/soong/android/config.BuildFromTextStub()] is true. +// +// - "framework-foo.stubs.exportable.<[apiScope.name]>" (type: [Library]): stub library module +// that provides the "exportable" stubs. "exportable" stubs are the stubs that do not +// include in-development flagged apis. This module is only used for SDK builds to generate +// the SDK artifacts, and not purposed for consumption for other modules. +// +// - "framework-foo.stubs.exportable.<[apiScope.name]>.from-source" (type: [Library]): stub +// library module that compiles the "exportable" stubs generated by the droidstubs +// submodule. This module is always a static dependency of the "exportable" stub library +// module given that from-text stubs cannot be used for SDK builds as it does not contain +// documentations. +// +// - "framework-foo.xml" (type: [sdkLibraryXml]): xml library that generates the permission xml +// file, which allows [SdkLibrary] to be used with <uses-permission> tag in the +// AndroidManifest.xml files. +// --------------------------------------------------------------------------------------------- + +// Creates the implementation [Library] with ".impl" suffix. +func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) { + visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility) + + staticLibs := module.properties.Static_libs.Clone() + staticLibs.AppendSimpleValue(module.sdkLibraryProperties.Impl_only_static_libs) + props := struct { + Name *string + Enabled proptools.Configurable[bool] + Visibility []string + Libs []string + Static_libs proptools.Configurable[[]string] + Apex_available []string + Stem *string + }{ + Name: proptools.StringPtr(module.implLibraryModuleName()), + Enabled: module.EnabledProperty(), + Visibility: visibility, + + Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...), + + Static_libs: staticLibs, + // Pass the apex_available settings down so that the impl library can be statically + // embedded within a library that is added to an APEX. Needed for updatable-media. + Apex_available: module.ApexAvailable(), + + Stem: proptools.StringPtr(module.Name()), + } + + properties := []interface{}{ + &module.properties, + &module.protoProperties, + &module.deviceProperties, + &module.dexProperties, + &module.dexpreoptProperties, + &module.linter.properties, + &module.overridableProperties, + &props, + module.sdkComponentPropertiesForChildLibrary(), + } + mctx.CreateModule(LibraryFactory, properties...) +} + +// Creates the [Droidstubs] module with ".stubs.source.<[apiScope.name]>" that creates stubs +// source files from the given full source files and also updates and checks the API +// specification files (i.e. "*-current.txt", "*-removed.txt" files). +func (module *SdkLibrary) createDroidstubs(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) { + props := struct { + Name *string + Enabled proptools.Configurable[bool] + Visibility []string + Srcs []string + Installable *bool + Sdk_version *string + Api_surface *string + System_modules *string + Libs proptools.Configurable[[]string] + Output_javadoc_comments *bool + Arg_files []string + Args *string + Java_version *string + Annotations_enabled *bool + Merge_annotations_dirs []string + Merge_inclusion_annotations_dirs []string + Generate_stubs *bool + Previous_api *string + Aconfig_declarations []string + Check_api struct { + Current ApiToCheck + Last_released ApiToCheck + + Api_lint struct { + Enabled *bool + New_since *string + Baseline_file *string + } + } + Aidl struct { + Include_dirs []string + Local_include_dirs []string + } + Dists []android.Dist + }{} + + // The stubs source processing uses the same compile time classpath when extracting the + // API from the implementation library as it does when compiling it. i.e. the same + // * sdk version + // * system_modules + // * libs (static_libs/libs) + + props.Name = proptools.StringPtr(name) + props.Enabled = module.EnabledProperty() + props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility) + props.Srcs = append(props.Srcs, module.properties.Srcs...) + props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...) + props.Sdk_version = module.deviceProperties.Sdk_version + props.Api_surface = &apiScope.name + props.System_modules = module.deviceProperties.System_modules + props.Installable = proptools.BoolPtr(false) + // A droiddoc module has only one Libs property and doesn't distinguish between + // shared libs and static libs. So we need to add both of these libs to Libs property. + props.Libs = proptools.NewConfigurable[[]string](nil, nil) + props.Libs.AppendSimpleValue(module.properties.Libs) + props.Libs.Append(module.properties.Static_libs) + props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs) + props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs) + props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs + props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs + props.Java_version = module.properties.Java_version + + props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled + props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs + props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs + props.Aconfig_declarations = module.sdkLibraryProperties.Aconfig_declarations + + droidstubsArgs := []string{} + if len(module.sdkLibraryProperties.Api_packages) != 0 { + droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":")) + } + droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...) + disabledWarnings := []string{"HiddenSuperclass"} + if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) { + disabledWarnings = append(disabledWarnings, + "BroadcastBehavior", + "DeprecationMismatch", + "MissingPermission", + "SdkConstant", + "Todo", + ) + } + droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide ")) + + // Output Javadoc comments for public scope. + if apiScope == apiScopePublic { + props.Output_javadoc_comments = proptools.BoolPtr(true) + } + + // Add in scope specific arguments. + droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...) + props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files + props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " ")) + + // List of APIs identified from the provided source files are created. They are later + // compared against to the not-yet-released (a.k.a current) list of APIs and to the + // last-released (a.k.a numbered) list of API. + currentApiFileName := apiScope.apiFilePrefix + "current.txt" + removedApiFileName := apiScope.apiFilePrefix + "removed.txt" + apiDir := module.getApiDir() + currentApiFileName = path.Join(apiDir, currentApiFileName) + removedApiFileName = path.Join(apiDir, removedApiFileName) + + // check against the not-yet-release API + props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName) + props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName) + + if module.compareAgainstLatestApi(apiScope) { + // check against the latest released API + latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) + props.Previous_api = latestApiFilegroupName + props.Check_api.Last_released.Api_file = latestApiFilegroupName + props.Check_api.Last_released.Removed_api_file = proptools.StringPtr( + module.latestRemovedApiFilegroupName(apiScope)) + props.Check_api.Last_released.Baseline_file = proptools.StringPtr( + module.latestIncompatibilitiesFilegroupName(apiScope)) + + if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) { + // Enable api lint. + props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true) + props.Check_api.Api_lint.New_since = latestApiFilegroupName + + // If it exists then pass a lint-baseline.txt through to droidstubs. + baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt") + baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath) + paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil) + if err != nil { + mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err) + } + if len(paths) == 1 { + props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath) + } else if len(paths) != 0 { + mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths) + } + } + } + + if !Bool(module.sdkLibraryProperties.No_dist) { + // Dist the api txt and removed api txt artifacts for sdk builds. + distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api")) + stubsTypeTagPrefix := "" + if mctx.Config().ReleaseHiddenApiExportableStubs() { + stubsTypeTagPrefix = ".exportable" + } + for _, p := range []struct { + tag string + pattern string + }{ + // "exportable" api files are copied to the dist directory instead of the + // "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag + // is set. Otherwise, the "everything" api files are copied to the dist directory. + {tag: "%s.api.txt", pattern: "%s.txt"}, + {tag: "%s.removed-api.txt", pattern: "%s-removed.txt"}, + } { + props.Dists = append(props.Dists, android.Dist{ + Targets: []string{"sdk", "win_sdk"}, + Dir: distDir, + Dest: proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())), + Tag: proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)), + }) + } + } + + mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx) +} + +type libraryProperties struct { + Name *string + Enabled proptools.Configurable[bool] + Visibility []string + Srcs []string + Installable *bool + Sdk_version *string + System_modules *string + Patch_module *string + Libs []string + Static_libs []string + Compile_dex *bool + Java_version *string + Openjdk9 struct { + Srcs []string + Javacflags []string + } + Dist struct { + Targets []string + Dest *string + Dir *string + Tag *string + } + Is_stubs_module *bool + Stub_contributing_api *string +} + +func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties { + props := libraryProperties{} + props.Enabled = module.EnabledProperty() + props.Visibility = []string{"//visibility:override", "//visibility:private"} + // sources are generated from the droiddoc + sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) + props.Sdk_version = proptools.StringPtr(sdkVersion) + props.System_modules = module.deviceProperties.System_modules + props.Patch_module = module.properties.Patch_module + props.Installable = proptools.BoolPtr(false) + props.Libs = module.sdkLibraryProperties.Stub_only_libs + props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...) + props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs + // The stub-annotations library contains special versions of the annotations + // with CLASS retention policy, so that they're kept. + if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) { + props.Libs = append(props.Libs, "stub-annotations") + } + props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs + props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags + // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential + // interop with older developer tools that don't support 1.9. + props.Java_version = proptools.StringPtr("1.8") + props.Is_stubs_module = proptools.BoolPtr(true) + props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String()) + + return props +} + +// Creates the from-source stub [Library] with ".stubs.<[apiScope.name]>.from-source" suffix. +func (module *SdkLibrary) createFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { + + props := module.stubsLibraryProps(mctx, apiScope) + props.Name = proptools.StringPtr(module.fromSourceStubsLibraryModuleName(apiScope)) + props.Srcs = []string{":" + module.droidstubsModuleName(apiScope)} + + mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) +} + +// Creates the "exportable" from-source stub [Library] with +// ".stubs.exportable.<[apiScope.name]>" suffix. +func (module *SdkLibrary) createExportableFromSourceStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { + props := module.stubsLibraryProps(mctx, apiScope) + props.Name = proptools.StringPtr(module.exportableFromSourceStubsLibraryModuleName(apiScope)) + props.Srcs = []string{":" + module.droidstubsModuleName(apiScope) + "{.exportable}"} + + mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) +} + +// Creates the from-text stub [ApiLibrary] with ".stubs.<[apiScope.name]>.from-text" suffix. +func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) { + props := struct { + Name *string + Enabled proptools.Configurable[bool] + Visibility []string + Api_contributions []string + Libs proptools.Configurable[[]string] + Static_libs []string + System_modules *string + Enable_validation *bool + Stubs_type *string + Sdk_version *string + Previous_api *string + }{} + + props.Name = proptools.StringPtr(module.fromTextStubsLibraryModuleName(apiScope)) + props.Enabled = module.EnabledProperty() + props.Visibility = []string{"//visibility:override", "//visibility:private"} + + apiContributions := []string{} + + // Api surfaces are not independent of each other, but have subset relationships, + // and so does the api files. To generate from-text stubs for api surfaces other than public, + // all subset api domains' api_contriubtions must be added as well. + scope := apiScope + for scope != nil { + apiContributions = append(apiContributions, module.droidstubsModuleName(scope)+".api.contribution") + scope = scope.extends + } + if apiScope == apiScopePublic { + additionalApiContribution := module.apiLibraryAdditionalApiContribution() + if additionalApiContribution != "" { + apiContributions = append(apiContributions, additionalApiContribution) + } + } + + props.Api_contributions = apiContributions + + // Ensure that stub-annotations is added to the classpath before any other libs + props.Libs = proptools.NewConfigurable[[]string](nil, nil) + props.Libs.AppendSimpleValue([]string{"stub-annotations"}) + props.Libs.AppendSimpleValue(module.properties.Libs) + props.Libs.Append(module.properties.Static_libs) + props.Libs.AppendSimpleValue(module.sdkLibraryProperties.Stub_only_libs) + props.Libs.AppendSimpleValue(module.scopeToProperties[apiScope].Libs) + props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs + + props.System_modules = module.deviceProperties.System_modules + props.Enable_validation = proptools.BoolPtr(true) + props.Stubs_type = proptools.StringPtr("everything") + + if module.deviceProperties.Sdk_version != nil { + props.Sdk_version = module.deviceProperties.Sdk_version + } + + if module.compareAgainstLatestApi(apiScope) { + // check against the latest released API + latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope)) + props.Previous_api = latestApiFilegroupName + } + + mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) +} + +func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties { + props := libraryProperties{} + + props.Enabled = module.EnabledProperty() + props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) + sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) + props.Sdk_version = proptools.StringPtr(sdkVersion) + + props.System_modules = module.deviceProperties.System_modules + + // The imports need to be compiled to dex if the java_sdk_library requests it. + compileDex := module.dexProperties.Compile_dex + if module.stubLibrariesCompiledForDex() { + compileDex = proptools.BoolPtr(true) + } + props.Compile_dex = compileDex + + props.Stub_contributing_api = proptools.StringPtr(apiScope.kind.String()) + + if !Bool(module.sdkLibraryProperties.No_dist) && doDist { + props.Dist.Targets = []string{"sdk", "win_sdk"} + props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem())) + props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope)) + props.Dist.Tag = proptools.StringPtr(".jar") + } + props.Is_stubs_module = proptools.BoolPtr(true) + + return props +} + +// Creates the stub [Library] with ".stubs.<[apiScope.name]>" suffix. +func (module *SdkLibrary) createTopLevelStubsLibrary( + mctx android.DefaultableHookContext, apiScope *apiScope) { + + // Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false + doDist := !mctx.Config().ReleaseHiddenApiExportableStubs() + props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist) + props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) + + // Add the stub compiling java_library/java_api_library as static lib based on build config + staticLib := module.fromSourceStubsLibraryModuleName(apiScope) + if mctx.Config().BuildFromTextStub() && module.ModuleBuildFromTextStubs() { + staticLib = module.fromTextStubsLibraryModuleName(apiScope) + } + props.Static_libs = append(props.Static_libs, staticLib) + + mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) +} + +// Creates the "exportable" stub [Library] with ".stubs.exportable.<[apiScope.name]>" suffix. +func (module *SdkLibrary) createTopLevelExportableStubsLibrary( + mctx android.DefaultableHookContext, apiScope *apiScope) { + + // Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true + doDist := mctx.Config().ReleaseHiddenApiExportableStubs() + props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist) + props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope)) + + staticLib := module.exportableFromSourceStubsLibraryModuleName(apiScope) + props.Static_libs = append(props.Static_libs, staticLib) + + mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary()) +} + +// Creates the [sdkLibraryXml] with ".xml" suffix. +func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { + moduleMinApiLevel := module.Library.MinSdkVersion(mctx) + var moduleMinApiLevelStr = moduleMinApiLevel.String() + if moduleMinApiLevel == android.NoneApiLevel { + moduleMinApiLevelStr = "current" + } + props := struct { + Name *string + Enabled proptools.Configurable[bool] + Lib_name *string + Apex_available []string + On_bootclasspath_since *string + On_bootclasspath_before *string + Min_device_sdk *string + Max_device_sdk *string + Sdk_library_min_api_level *string + Uses_libs_dependencies []string + }{ + Name: proptools.StringPtr(module.xmlPermissionsModuleName()), + Enabled: module.EnabledProperty(), + Lib_name: proptools.StringPtr(module.BaseModuleName()), + Apex_available: module.ApexProperties.Apex_available, + On_bootclasspath_since: module.commonSdkLibraryProperties.On_bootclasspath_since, + On_bootclasspath_before: module.commonSdkLibraryProperties.On_bootclasspath_before, + Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk, + Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk, + Sdk_library_min_api_level: &moduleMinApiLevelStr, + Uses_libs_dependencies: module.usesLibraryProperties.Uses_libs, + } + + mctx.CreateModule(sdkLibraryXmlFactory, &props) +} + +// --------------------------------------------------------------------------------------------- +// Build rules of the submodules generated by java_sdk_library_import. +// Note that the java_sdk_library_import module does not generate the implementation library. +// Instead, it will create a dependency to the source implemenetation library if one exists. +// java_sdk_library_import "framework-foo" generates the following submodules: +// +// - "framework-foo.stubs.<[apiScope.name]>" (type: [Import]): prebuilt stub library module that +// provides the stub jar file checked in the tree. +// +// - "framework-foo.stubs.source.<[apiScope.name]>" (type: [PrebuiltStubsSources]): prebuilt +// droidstubs module that provides the stub source jar file checked in the tree. +// +// - "framework-foo.stubs.source.<[apiScope.name]>.api.contribution" +// (type [JavaApiContributionImport]): prebuilt java_api_contribution module that provides +// the prebuilt api file for previously released from-text stub generation. +// --------------------------------------------------------------------------------------------- + +// Creates the prebuilt stub [Import] with ".stubs.<[apiScope.name]>" suffix. +func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { + // Creates a java import for the jar with ".stubs" suffix + props := struct { + Name *string + Source_module_name *string + Created_by_java_sdk_library_name *string + Sdk_version *string + Libs []string + Jars []string + Compile_dex *bool + Is_stubs_module *bool + + android.UserSuppliedPrebuiltProperties + }{} + props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) + props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName())) + props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) + props.Sdk_version = scopeProperties.Sdk_version + // Prepend any of the libs from the legacy public properties to the libs for each of the + // scopes to avoid having to duplicate them in each scope. + props.Libs = append(module.properties.Libs, scopeProperties.Libs...) + props.Jars = scopeProperties.Jars + + // The imports are preferred if the java_sdk_library_import is preferred. + props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) + + // The imports need to be compiled to dex if the java_sdk_library_import requests it. + compileDex := module.properties.Compile_dex + if module.stubLibrariesCompiledForDex() { + compileDex = proptools.BoolPtr(true) + } + props.Compile_dex = compileDex + props.Is_stubs_module = proptools.BoolPtr(true) + + mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) +} + +func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { + props := struct { + Name *string + Source_module_name *string + Created_by_java_sdk_library_name *string + Srcs []string + + android.UserSuppliedPrebuiltProperties + }{} + props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope)) + props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName())) + props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) + props.Srcs = scopeProperties.Stub_srcs + + // The stubs source is preferred if the java_sdk_library_import is preferred. + props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt) + + mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary()) +} + +// Creates the prebuilt api contribution [JavaApiContributionImport] with +// ".stubs.source.<[apiScope.name]>.api.contribution" suffix. +func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) { + api_file := scopeProperties.Current_api + api_surface := &apiScope.name + + props := struct { + Name *string + Source_module_name *string + Created_by_java_sdk_library_name *string + Api_surface *string + Api_file *string + Visibility []string + }{} + + props.Name = proptools.StringPtr(module.droidstubsModuleName(apiScope) + ".api.contribution") + props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution") + props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName()) + props.Api_surface = api_surface + props.Api_file = api_file + props.Visibility = []string{"//visibility:override", "//visibility:public"} + + mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary()) +} + +// --------------------------------------------------------------------------------------------- +// End of the build rules of the submodules generated by java_sdk_library_import. +// --------------------------------------------------------------------------------------------- + +// Definition of the [sdkLibraryXml] module. The module generates the permissions xml file, +// so that the apps can specify the java_sdk_library using <uses-permission> tag in the +// AndroidManifest.xml file. +type sdkLibraryXml struct { + android.ModuleBase + android.DefaultableModuleBase + android.ApexModuleBase + + properties sdkLibraryXmlProperties + + outputFilePath android.OutputPath + installDirPath android.InstallPath + + hideApexVariantFromMake bool +} + +type sdkLibraryXmlProperties struct { + // canonical name of the lib + Lib_name *string + + // Signals that this shared library is part of the bootclasspath starting + // on the version indicated in this attribute. + // + // This will make platforms at this level and above to ignore + // <uses-library> tags with this library name because the library is already + // available + On_bootclasspath_since *string + + // Signals that this shared library was part of the bootclasspath before + // (but not including) the version indicated in this attribute. + // + // The system will automatically add a <uses-library> tag with this library to + // apps that target any SDK less than the version indicated in this attribute. + On_bootclasspath_before *string + + // Indicates that PackageManager should ignore this shared library if the + // platform is below the version indicated in this attribute. + // + // This means that the device won't recognise this library as installed. + Min_device_sdk *string + + // Indicates that PackageManager should ignore this shared library if the + // platform is above the version indicated in this attribute. + // + // This means that the device won't recognise this library as installed. + Max_device_sdk *string + + // The SdkLibrary's min api level as a string + // + // This value comes from the ApiLevel of the MinSdkVersion property. + Sdk_library_min_api_level *string + + // Uses-libs dependencies that the shared library requires to work correctly. + // + // This will add dependency="foo:bar" to the <library> section. + Uses_libs_dependencies []string +} + +// java_sdk_library_xml builds the permission xml file for a java_sdk_library. +// Not to be used directly by users. java_sdk_library internally uses this. +func sdkLibraryXmlFactory() android.Module { + module := &sdkLibraryXml{} + + module.AddProperties(&module.properties) + + android.InitApexModule(module) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + + return module +} + +func (module *sdkLibraryXml) UniqueApexVariations() bool { + // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the + // mounted APEX, which contains the name of the APEX. + return true +} + +// from android.PrebuiltEtcModule +func (module *sdkLibraryXml) BaseDir() string { + return "etc" +} + +// from android.PrebuiltEtcModule +func (module *sdkLibraryXml) SubDir() string { + return "permissions" +} + +var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil) + +// from android.ApexModule +func (module *sdkLibraryXml) AvailableFor(what string) bool { + return true +} + +func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { + // do nothing +} + +var _ android.ApexModule = (*sdkLibraryXml)(nil) + +// Implements android.ApexModule +func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, + sdkVersion android.ApiLevel) error { + // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked + return nil +} + +// File path to the runtime implementation library +func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string { + implName := proptools.String(module.properties.Lib_name) + if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() { + // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name. + // In most cases, this works fine. But when apex_name is set or override_apex is used + // this can be wrong. + return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexInfo.BaseApexName, implName) + } + partition := "system" + if module.SocSpecific() { + partition = "vendor" + } else if module.DeviceSpecific() { + partition = "odm" + } else if module.ProductSpecific() { + partition = "product" + } else if module.SystemExtSpecific() { + partition = "system_ext" + } + return "/" + partition + "/framework/" + implName + ".jar" +} + +func formattedOptionalSdkLevelAttribute(ctx android.ModuleContext, attrName string, value *string) string { + if value == nil { + return "" + } + apiLevel, err := android.ApiLevelFromUser(ctx, *value) + if err != nil { + // attributes in bp files have underscores but in the xml have dashes. + ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), err.Error()) + return "" + } + if apiLevel.IsCurrent() { + // passing "current" would always mean a future release, never the current (or the current in + // progress) which means some conditions would never be triggered. + ctx.PropertyErrorf(strings.ReplaceAll(attrName, "-", "_"), + `"current" is not an allowed value for this attribute`) + return "" + } + // "safeValue" is safe because it translates finalized codenames to a string + // with their SDK int. + safeValue := apiLevel.String() + return formattedOptionalAttribute(attrName, &safeValue) +} + +// formats an attribute for the xml permissions file if the value is not null +// returns empty string otherwise +func formattedOptionalAttribute(attrName string, value *string) string { + if value == nil { + return "" + } + 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, ":")) +} + +func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string { + libName := proptools.String(module.properties.Lib_name) + libNameAttr := formattedOptionalAttribute("name", &libName) + filePath := module.implPath(ctx) + filePathAttr := formattedOptionalAttribute("file", &filePath) + implicitFromAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-since", module.properties.On_bootclasspath_since) + implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before) + minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk) + maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk) + dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies) + // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that). + // 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" + } else { + 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", + libraryTag, + libNameAttr, + filePathAttr, + implicitFromAttr, + implicitUntilAttr, + minSdkAttr, + maxSdkAttr, + dependenciesAttr, + " />\n", + "</permissions>\n", + }, "") +} + +func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) { + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) + module.hideApexVariantFromMake = !apexInfo.IsForPlatform() + + libName := proptools.String(module.properties.Lib_name) + module.selfValidate(ctx) + xmlContent := module.permissionsContents(ctx) + + module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath + android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent) + + module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir()) + ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath) + + ctx.SetOutputFiles(android.OutputPaths{module.outputFilePath}.Paths(), "") +} + +func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries { + if module.hideApexVariantFromMake { + return []android.AndroidMkEntries{{ + Disabled: true, + }} + } + + return []android.AndroidMkEntries{{ + Class: "ETC", + OutputFile: android.OptionalPathForPath(module.outputFilePath), + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.SetString("LOCAL_MODULE_TAGS", "optional") + entries.SetString("LOCAL_MODULE_PATH", module.installDirPath.String()) + entries.SetString("LOCAL_INSTALLED_MODULE_STEM", module.outputFilePath.Base()) + }, + }, + }} +} + +func (module *sdkLibraryXml) selfValidate(ctx android.ModuleContext) { + module.validateAtLeastTAttributes(ctx) + module.validateMinAndMaxDeviceSdk(ctx) + module.validateMinMaxDeviceSdkAndModuleMinSdk(ctx) + module.validateOnBootclasspathBeforeRequirements(ctx) +} + +func (module *sdkLibraryXml) validateAtLeastTAttributes(ctx android.ModuleContext) { + t := android.ApiLevelOrPanic(ctx, "Tiramisu") + module.attrAtLeastT(ctx, t, module.properties.Min_device_sdk, "min_device_sdk") + module.attrAtLeastT(ctx, t, module.properties.Max_device_sdk, "max_device_sdk") + module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_before, "on_bootclasspath_before") + module.attrAtLeastT(ctx, t, module.properties.On_bootclasspath_since, "on_bootclasspath_since") +} + +func (module *sdkLibraryXml) attrAtLeastT(ctx android.ModuleContext, t android.ApiLevel, attr *string, attrName string) { + if attr != nil { + if level, err := android.ApiLevelFromUser(ctx, *attr); err == nil { + // we will inform the user of invalid inputs when we try to write the + // permissions xml file so we don't need to do it here + if t.GreaterThan(level) { + ctx.PropertyErrorf(attrName, "Attribute value needs to be at least T") + } + } + } +} + +func (module *sdkLibraryXml) validateMinAndMaxDeviceSdk(ctx android.ModuleContext) { + if module.properties.Min_device_sdk != nil && module.properties.Max_device_sdk != nil { + min, minErr := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) + max, maxErr := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) + if minErr == nil && maxErr == nil { + // we will inform the user of invalid inputs when we try to write the + // permissions xml file so we don't need to do it here + if min.GreaterThan(max) { + ctx.ModuleErrorf("min_device_sdk can't be greater than max_device_sdk") + } + } + } +} + +func (module *sdkLibraryXml) validateMinMaxDeviceSdkAndModuleMinSdk(ctx android.ModuleContext) { + moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) + if module.properties.Min_device_sdk != nil { + api, err := android.ApiLevelFromUser(ctx, *module.properties.Min_device_sdk) + if err == nil { + if moduleMinApi.GreaterThan(api) { + ctx.PropertyErrorf("min_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) + } + } + } + if module.properties.Max_device_sdk != nil { + api, err := android.ApiLevelFromUser(ctx, *module.properties.Max_device_sdk) + if err == nil { + if moduleMinApi.GreaterThan(api) { + ctx.PropertyErrorf("max_device_sdk", "Can't be less than module's min sdk (%s)", moduleMinApi) + } + } + } +} + +func (module *sdkLibraryXml) validateOnBootclasspathBeforeRequirements(ctx android.ModuleContext) { + moduleMinApi := android.ApiLevelOrPanic(ctx, *module.properties.Sdk_library_min_api_level) + if module.properties.On_bootclasspath_before != nil { + t := android.ApiLevelOrPanic(ctx, "Tiramisu") + // if we use the attribute, then we need to do this validation + if moduleMinApi.LessThan(t) { + // if minAPi is < T, then we need to have min_device_sdk (which only accepts T+) + if module.properties.Min_device_sdk == nil { + ctx.PropertyErrorf("on_bootclasspath_before", "Using this property requires that the module's min_sdk_version or the shared library's min_device_sdk is at least T") + } + } + } +} diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index bb6331506..6031d7230 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -22,8 +22,6 @@ import ( "testing" "android/soong/android" - - "github.com/google/blueprint/proptools" ) func TestJavaSdkLibrary(t *testing.T) { @@ -55,7 +53,7 @@ func TestJavaSdkLibrary(t *testing.T) { java_library { name: "baz", srcs: ["c.java"], - libs: ["foo", "bar.stubs"], + libs: ["foo.stubs.system", "bar.stubs"], sdk_version: "system_current", } java_sdk_library { @@ -92,25 +90,25 @@ func TestJavaSdkLibrary(t *testing.T) { java_library { name: "qux", srcs: ["c.java"], - libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"], + libs: ["baz", "fred.stubs", "quuz.stubs", "wilma.stubs", "barney.stubs.system", "betty.stubs.system"], sdk_version: "system_current", } java_library { name: "baz-test", srcs: ["c.java"], - libs: ["foo"], + libs: ["foo.stubs.test"], sdk_version: "test_current", } java_library { name: "baz-29", srcs: ["c.java"], - libs: ["foo"], + libs: ["sdk_system_29_foo"], sdk_version: "system_29", } java_library { name: "baz-module-30", srcs: ["c.java"], - libs: ["foo"], + libs: ["sdk_module-lib_30_foo"], sdk_version: "module_30", } `) @@ -162,11 +160,11 @@ func TestJavaSdkLibrary(t *testing.T) { baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac") // tests if baz-29 is actually linked to the system 29 stubs lib - android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") + android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/sdk_system_29_foo/android_common/combined/sdk_system_29_foo.jar") bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac") // tests if "baz-module-30" is actually linked to the module 30 stubs lib - android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar") + android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/sdk_module-lib_30_foo/android_common/combined/sdk_module-lib_30_foo.jar") // test if baz has exported SDK lib names foo and bar to qux qux := result.ModuleForTests("qux", "android_common") @@ -422,7 +420,7 @@ func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { for _, expectation := range expectations { verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined) - stubName := apiScopePublic.sourceStubLibraryModuleName("sdklib") + stubName := apiScopePublic.sourceStubsLibraryModuleName("sdklib") verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined) } } @@ -445,7 +443,7 @@ func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) { java_library { name: "bar", srcs: ["b.java"], - libs: ["foo"], + libs: ["foo.stubs"], } `) @@ -763,7 +761,7 @@ func TestJavaSdkLibrary_SystemServer_AccessToStubScopeLibs(t *testing.T) { java_library { name: "bar", srcs: ["a.java"], - libs: ["foo-public", "foo-system", "foo-module-lib", "foo-system-server"], + libs: ["foo-public.stubs", "foo-system.stubs.system", "foo-module-lib.stubs.module_lib", "foo-system-server.stubs.system_server"], sdk_version: "system_server_current", } `) @@ -789,102 +787,26 @@ func TestJavaSdkLibrary_SystemServer_AccessToStubScopeLibs(t *testing.T) { } } -func TestJavaSdkLibrary_MissingScope(t *testing.T) { - prepareForJavaTest. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)). - RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - public: { - enabled: false, - }, - } - - java_library { - name: "baz", - srcs: ["a.java"], - libs: ["foo"], - sdk_version: "module_current", - } - `) -} - -func TestJavaSdkLibrary_FallbackScope(t *testing.T) { - android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - system: { - enabled: true, - }, - } - - java_library { - name: "baz", - srcs: ["a.java"], - libs: ["foo"], - // foo does not have module-lib scope so it should fallback to system - sdk_version: "module_current", - } - `) -} - -func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) { - result := android.GroupFixturePreparers( - prepareForJavaTest, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("foo"), - ).RunTestWithBp(t, ` - java_sdk_library { - name: "foo", - srcs: ["a.java"], - system: { - enabled: true, - }, - default_to_stubs: true, - } - - java_library { - name: "baz", - srcs: ["a.java"], - libs: ["foo"], - // does not have sdk_version set, should fallback to module, - // which will then fallback to system because the module scope - // is not enabled. - } - `) - // The baz library should depend on the system stubs jar. - bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac") - if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { - t.Errorf("expected %q, found %#q", expected, actual) - } -} - func TestJavaSdkLibraryImport(t *testing.T) { result := prepareForJavaTest.RunTestWithBp(t, ` java_library { name: "foo", srcs: ["a.java"], - libs: ["sdklib"], + libs: ["sdklib.stubs"], sdk_version: "current", } java_library { name: "foo.system", srcs: ["a.java"], - libs: ["sdklib"], + libs: ["sdklib.stubs.system"], sdk_version: "system_current", } java_library { name: "foo.test", srcs: ["a.java"], - libs: ["sdklib"], + libs: ["sdklib.stubs.test"], sdk_version: "test_current", } @@ -1017,7 +939,7 @@ func testJavaSdkLibraryImport_Preferred(t *testing.T, prefer string, preparer an java_library { name: "public", srcs: ["a.java"], - libs: ["sdklib"], + libs: ["sdklib.stubs"], sdk_version: "current", } `) @@ -1190,155 +1112,6 @@ func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) { } } -func TestJavaSdkLibraryEnforce(t *testing.T) { - partitionToBpOption := func(partition string) string { - switch partition { - case "system": - return "" - case "vendor": - return "soc_specific: true," - case "product": - return "product_specific: true," - default: - panic("Invalid partition group name: " + partition) - } - } - - type testConfigInfo struct { - libraryType string - fromPartition string - toPartition string - enforceProductInterface bool - enforceJavaSdkLibraryCheck bool - allowList []string - } - - createPreparer := func(info testConfigInfo) android.FixturePreparer { - bpFileTemplate := ` - java_library { - name: "foo", - srcs: ["foo.java"], - libs: ["bar"], - sdk_version: "current", - %s - } - - %s { - name: "bar", - srcs: ["bar.java"], - sdk_version: "current", - %s - } - ` - - bpFile := fmt.Sprintf(bpFileTemplate, - partitionToBpOption(info.fromPartition), - info.libraryType, - partitionToBpOption(info.toPartition)) - - return android.GroupFixturePreparers( - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("bar"), - android.FixtureWithRootAndroidBp(bpFile), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface) - variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck) - variables.InterPartitionJavaLibraryAllowList = info.allowList - }), - ) - } - - runTest := func(t *testing.T, info testConfigInfo, expectedErrorPattern string) { - t.Run(fmt.Sprintf("%v", info), func(t *testing.T) { - errorHandler := android.FixtureExpectsNoErrors - if expectedErrorPattern != "" { - errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern) - } - android.GroupFixturePreparers( - prepareForJavaTest, - createPreparer(info), - ). - ExtendWithErrorHandler(errorHandler). - RunTest(t) - }) - } - - errorMessage := "is not allowed across the partitions" - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "product", - toPartition: "system", - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: false, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "product", - toPartition: "system", - enforceProductInterface: false, - enforceJavaSdkLibraryCheck: true, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "product", - toPartition: "system", - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, errorMessage) - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "vendor", - toPartition: "system", - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, errorMessage) - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "vendor", - toPartition: "system", - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - allowList: []string{"bar"}, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_library", - fromPartition: "vendor", - toPartition: "product", - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, errorMessage) - - runTest(t, testConfigInfo{ - libraryType: "java_sdk_library", - fromPartition: "product", - toPartition: "system", - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_sdk_library", - fromPartition: "vendor", - toPartition: "system", - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, "") - - runTest(t, testConfigInfo{ - libraryType: "java_sdk_library", - fromPartition: "vendor", - toPartition: "product", - enforceProductInterface: true, - enforceJavaSdkLibraryCheck: true, - }, "") -} - func TestJavaSdkLibraryDist(t *testing.T) { result := android.GroupFixturePreparers( PrepareForTestWithJavaBuildComponents, @@ -1657,7 +1430,7 @@ func TestSdkLibraryDependency(t *testing.T) { name: "bar", srcs: ["c.java", "b.java"], libs: [ - "foo", + "foo.stubs", ], uses_libs: [ "foo", @@ -1752,7 +1525,7 @@ func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) { name: "mymodule", srcs: ["a.java"], sdk_version: "current", - libs: ["sdklib",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt) + libs: ["sdklib.stubs",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt) } ` @@ -1893,3 +1666,111 @@ func TestStubLinkType(t *testing.T) { } `) } + +func TestSdkLibDirectDependency(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo", "bar"), + ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{ + `module "baz" variant "android_common": cannot depend directly on java_sdk_library ` + + `"foo"; try depending on "foo.stubs", or "foo.impl" instead`, + `module "baz" variant "android_common": cannot depend directly on java_sdk_library ` + + `"prebuilt_bar"; try depending on "bar.stubs", or "bar.impl" instead`, + }), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + public: { + enabled: true, + }, + } + + java_sdk_library_import { + name: "foo", + public: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", + }, + } + + java_sdk_library { + name: "bar", + srcs: ["a.java"], + sdk_version: "current", + public: { + enabled: true, + }, + } + + java_sdk_library_import { + name: "bar", + prefer: true, + public: { + jars: ["a.jar"], + stub_srcs: ["a.java"], + current_api: "current.txt", + removed_api: "removed.txt", + annotations: "annotations.zip", + }, + } + + java_library { + name: "baz", + srcs: ["b.java"], + libs: [ + "foo", + "bar", + ], + } + `) +} + +func TestSdkLibDirectDependencyWithPrebuiltSdk(t *testing.T) { + android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Platform_sdk_version = intPtr(34) + variables.Platform_sdk_codename = stringPtr("VanillaIceCream") + variables.Platform_version_active_codenames = []string{"VanillaIceCream"} + variables.Platform_systemsdk_versions = []string{"33", "34", "VanillaIceCream"} + variables.DeviceSystemSdkVersions = []string{"VanillaIceCream"} + }), + FixtureWithPrebuiltApis(map[string][]string{ + "33": {"foo"}, + "34": {"foo"}, + "35": {"foo"}, + }), + ).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern( + `module "baz" variant "android_common": cannot depend directly on java_sdk_library "foo"; `+ + `try depending on "sdk_public_33_foo", "sdk_system_33_foo", "sdk_test_33_foo", `+ + `"sdk_module-lib_33_foo", or "sdk_system-server_33_foo" instead`), + ).RunTestWithBp(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + public: { + enabled: true, + }, + system: { + enabled: true, + }, + } + + java_library { + name: "baz", + srcs: ["b.java"], + libs: [ + "foo", + ], + sdk_version: "system_33", + } + `) +} diff --git a/java/testing.go b/java/testing.go index 6ed605475..4615487fb 100644 --- a/java/testing.go +++ b/java/testing.go @@ -30,6 +30,7 @@ import ( ) const defaultJavaDir = "default/java" +const testDefaultUpdatableModuleVersion = "340090000" // Test fixture preparer that will register most java build components. // @@ -61,6 +62,7 @@ var PrepareForTestWithJavaBuildComponents = android.GroupFixturePreparers( // Needed for the global lint checks provided from frameworks/base "prebuilts/cmdline-tools/AndroidGlobalLintChecker.jar": nil, }.AddToFixture(), + android.PrepareForTestWithBuildFlag("RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION", testDefaultUpdatableModuleVersion), ) var prepareForTestWithFrameworkDeps = android.GroupFixturePreparers( @@ -388,7 +390,6 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { RegisterStubsBuildComponents(ctx) RegisterSystemModulesBuildComponents(ctx) registerSystemserverClasspathBuildComponents(ctx) - registerLintBuildComponents(ctx) android.RegisterApexContributionsBuildComponents(ctx) } |