diff options
Diffstat (limited to 'java')
59 files changed, 3411 insertions, 831 deletions
diff --git a/java/Android.bp b/java/Android.bp index 99d9c38a6..65200c27a 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -27,11 +27,13 @@ bootstrap_go_package { "android_manifest.go", "android_resources.go", "androidmk.go", + "apkcerts.go", "app_builder.go", "app.go", "app_import.go", "app_set.go", "base.go", + "base_gob_enc.go", "boot_jars.go", "bootclasspath.go", "bootclasspath_fragment.go", @@ -58,10 +60,12 @@ bootstrap_go_package { "hiddenapi_singleton.go", "jacoco.go", "java.go", + "java_gob_enc.go", "jdeps.go", "java_resources.go", "kotlin.go", "lint.go", + "lint_gob_enc.go", "legacy_core_platform_api_usage.go", "platform_bootclasspath.go", "platform_compat_config.go", @@ -76,6 +80,7 @@ bootstrap_go_package { "sdk_library_internal.go", "support_libraries.go", "system_modules.go", + "system_modules_gob_enc.go", "systemserver_classpath_fragment.go", "testing.go", "tracereferences.go", diff --git a/java/aapt2.go b/java/aapt2.go index bae4d1ee3..4efa6655a 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -52,14 +52,15 @@ func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.Writab } subDir := filepath.Dir(res.String()) subDir, lastDir := filepath.Split(subDir) - if isFlagsPath(subDir) { - var flag string + var flag string + if isFlagsPath(lastDir) { + flag = "." + strings.TrimPrefix(lastDir, "flag") + subDir, lastDir = filepath.Split(filepath.Dir(subDir)) + } else if isFlagsPath(subDir) { subDir, flag = filepath.Split(filepath.Dir(subDir)) - flag = strings.TrimPrefix(flag, "flag") - name = fmt.Sprintf("%s_%s.%s%s.flat", lastDir, name, flag, extension) - } else { - name = fmt.Sprintf("%s_%s%s.flat", lastDir, name, extension) + flag = "." + strings.TrimPrefix(flag, "flag") } + name = fmt.Sprintf("%s_%s%s%s.flat", lastDir, name, flag, extension) out := android.PathForModuleOut(ctx, "aapt2", subDir, name) return out } @@ -332,15 +333,20 @@ func aapt2ExtractExtraPackages(ctx android.ModuleContext, out android.WritablePa var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert", blueprint.RuleParams{ - Command: `${config.Aapt2Cmd} convert --enable-compact-entries ` + + Command: `${config.Aapt2Cmd} convert $flags ` + `--output-format $format $in -o $out`, CommandDeps: []string{"${config.Aapt2Cmd}"}, - }, "format", + }, "format", "flags", ) // Converts xml files and resource tables (resources.arsc) in the given jar/apk file to a proto // format. The proto definition is available at frameworks/base/tools/aapt2/Resources.proto. func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path, format string) { + extraFlags := []string{"--enable-compact-entries"} + if ctx.Config().ReleaseUseSparseEncoding() { + extraFlags = append(extraFlags, "--enable-sparse-encoding") + } + ctx.Build(pctx, android.BuildParams{ Rule: aapt2ConvertRule, Input: in, @@ -348,6 +354,7 @@ func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in androi Description: "convert to " + format, Args: map[string]string{ "format": format, + "flags": strings.Join(extraFlags, " "), }, }) } diff --git a/java/aar.go b/java/aar.go index ad080aa62..c1129f0c8 100644 --- a/java/aar.go +++ b/java/aar.go @@ -108,6 +108,9 @@ type aaptProperties struct { // Names of aconfig_declarations modules that specify aconfig flags that the module depends on. Flags_packages []string + + // The package name of this app. May not be used if `manifest` or `additional_manifests` are provided. + Package_name proptools.Configurable[string] } type aapt struct { @@ -144,6 +147,10 @@ type aapt struct { manifestValues struct { applicationId string } + + // Fields written to jdeps + assetDirs android.Paths + resourceDirs android.Paths } type split struct { @@ -263,6 +270,13 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...) linkFlags = append(linkFlags, "--enable-compact-entries") + if ctx.Config().ReleaseUseSparseEncoding() { + linkFlags = append(linkFlags, "--enable-sparse-encoding") + } + + if ctx.Config().ReleaseUseUncompressedFonts() { + linkFlags = append(linkFlags, "--no-compress-fonts") + } // Find implicit or explicit asset and resource dirs assets := android.PathsRelativeToModuleSourceDir(android.SourceInput{ @@ -276,7 +290,10 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte } else { assetDirs = android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") } + a.assetDirs = assetDirs + resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs.GetOrDefault(ctx, nil), "res") + a.resourceDirs = resourceDirs resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips) // Glob directories into lists of paths @@ -452,9 +469,21 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio opts.classLoaderContexts = opts.classLoaderContexts.ExcludeLibs(opts.excludedLibs) // App manifest file + packageNameProp := a.aaptProperties.Package_name.Get(ctx) var manifestFilePath android.Path if opts.manifestForAapt != nil { manifestFilePath = opts.manifestForAapt + } else if a.isLibrary && packageNameProp.IsPresent() && a.aaptProperties.Manifest == nil && a.aaptProperties.Additional_manifests == nil { + // If the only reason that a library needs a manifest file is to give the package name, allow them to do that in + // the module declaration. If they are already supplying a manifest, then do not autogenerate a manifest file. + generatedManifestPath := android.PathForModuleOut(ctx, "GeneratedManifest.xml") + manifestString := `<?xml version="1.0" encoding="utf-8"?> +<!-- Automatically generated by Soong. --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="` + packageNameProp.Get() + `" /> +` + android.WriteFileRule(ctx, generatedManifestPath, manifestString) + ctx.SetOutputFiles([]android.Path{generatedManifestPath}, ".gen_xml") + manifestFilePath = generatedManifestPath } else { manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") manifestFilePath = android.PathForModuleSrc(ctx, manifestFile) @@ -975,6 +1004,17 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { } func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { + packageNameProp := a.aaptProperties.Package_name.Get(ctx) + if packageNameProp.IsPresent() { + if a.aaptProperties.Manifest != nil { + ctx.PropertyErrorf("package_name", "cannot be used with `manifest`") + return + } + if a.aaptProperties.Additional_manifests != nil { + ctx.PropertyErrorf("package_name", "cannot be used with `additional_manifests`") + return + } + } a.aapt.isLibrary = true a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) if a.usesLibrary.shouldDisableDexpreopt { @@ -1042,6 +1082,7 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) var res android.Paths if a.androidLibraryProperties.BuildAAR { BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res) + android.SetProvider(ctx, AARProvider, AARInfo{Aar: a.aarFile}) } prebuiltJniPackages := android.Paths{} @@ -1070,6 +1111,11 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) a.setOutputFiles(ctx) buildComplianceMetadata(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + moduleInfoJSON.ClassesJar = []string{a.Library.implementationAndResourcesJar.String()} + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (a *AndroidLibrary) setOutputFiles(ctx android.ModuleContext) { @@ -1086,6 +1132,8 @@ func (a *aapt) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { if a.rJar != nil { dpInfo.Jars = append(dpInfo.Jars, a.rJar.String()) } + dpInfo.Asset_dirs = append(dpInfo.Asset_dirs, a.assetDirs.Strings()...) + dpInfo.Resource_dirs = append(dpInfo.Resource_dirs, a.resourceDirs.Strings()...) } // android_library builds and links sources into a `.jar` file for the device along with Android resources. @@ -1248,10 +1296,6 @@ func (a *AARImport) Name() string { return a.prebuilt.Name(a.ModuleBase.Name()) } -func (a *AARImport) JacocoReportClassesFile() android.Path { - return nil -} - func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { if !ctx.Config().AlwaysUsePrebuiltSdks() { sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) @@ -1267,6 +1311,7 @@ func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs.GetOrDefault(ctx, nil)...) a.usesLibrary.deps(ctx, false) + a.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } type JniPackageInfo struct { @@ -1585,6 +1630,11 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.SetOutputFiles([]android.Path{a.aarPath}, ".aar") buildComplianceMetadata(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + moduleInfoJSON.ClassesJar = []string{a.implementationAndResourcesJarFile.String()} + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (a *AARImport) HeaderJars() android.Paths { @@ -1656,5 +1706,12 @@ func AARImportFactory() android.Module { } func (a *AARImport) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { - dpInfo.Jars = append(dpInfo.Jars, a.implementationJarFile.String(), a.rJar.String()) + dpInfo.Jars = append(dpInfo.Jars, a.implementationJarFile.String(), a.rJar.String(), a.aarPath.String()) + dpInfo.Static_libs = append(dpInfo.Static_libs, a.properties.Static_libs.GetOrDefault(ctx, nil)...) +} + +type AARInfo struct { + Aar android.Path } + +var AARProvider = blueprint.NewProvider[AARInfo]() diff --git a/java/aar_test.go b/java/aar_test.go index 088ad6c92..520759682 100644 --- a/java/aar_test.go +++ b/java/aar_test.go @@ -131,7 +131,7 @@ func TestLibraryFlagsPackages(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 link command expected to pass feature flags arguments", linkInFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) } @@ -181,3 +181,29 @@ func TestAndroidLibraryOutputFilesRel(t *testing.T) { android.AssertStringEquals(t, "baz relative output path", "baz.jar", bazOutputPaths[0].Rel()) } + +func TestAndroidLibraryManifests(t *testing.T) { + t.Parallel() + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, ` + android_library { + name: "foo", + package_name: "com.android.foo", + java_resources: ["foo.txt"], + } + `) + + foo := result.ModuleForTests(t, "foo", "android_common") + + fooOutputPaths := foo.OutputFiles(result.TestContext, t, "") + + android.AssertPathsRelativeToTopEquals(t, "foo manifest path", + []string{"out/soong/.intermediates/foo/android_common/GeneratedManifest.xml"}, + foo.OutputFiles(result.TestContext, t, ".gen_xml")) + android.AssertPathsRelativeToTopEquals(t, "foo output path", + []string{"out/soong/.intermediates/foo/android_common/withres/foo.jar"}, fooOutputPaths) + + android.AssertStringEquals(t, "foo relative output path", + "foo.jar", fooOutputPaths[0].Rel()) +} diff --git a/java/android_manifest.go b/java/android_manifest.go index 7dd95c9ac..a7453ee6b 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -68,7 +68,7 @@ func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionLev return false } // If this a module targeting an unreleased SDK (MTS or unbundled builds), return 10000 - return targetSdkVersionLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) + return targetSdkVersionLevel.IsPreview() && (ctx.Config().HasUnbundledBuildApps() || includedInMts(ctx.Module())) } // Helper function that returns true if android_test, android_test_helper_app, java_test are in an MTS suite. diff --git a/java/androidmk.go b/java/androidmk.go index f155232de..97707d76b 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -102,8 +102,8 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar) entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile) - if library.jacocoReportClassesFile != nil { - entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile) + if library.jacocoInfo.ReportClassesFile != nil { + entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoInfo.ReportClassesFile) } requiredUsesLibs, optionalUsesLibs := library.classLoaderContexts.UsesLibs() @@ -113,8 +113,6 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip) entries.SetString("LOCAL_MODULE_STEM", library.Stem()) - entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports) - if library.dexpreopter.configPath != nil { entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath) } @@ -336,8 +334,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if app.bundleFile != nil { entries.SetPath("LOCAL_SOONG_BUNDLE", app.bundleFile) } - if app.jacocoReportClassesFile != nil { - entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile) + if app.jacocoInfo.ReportClassesFile != nil { + entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoInfo.ReportClassesFile) } entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary) entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.dexer.proguardUsageZip) @@ -359,7 +357,7 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", app.getOverriddenPackages()...) if app.embeddedJniLibs { - jniSymbols := app.JNISymbolsInstalls(app.installPathForJNISymbols.String()) + jniSymbols := JNISymbolsInstalls(app.jniLibs, app.installPathForJNISymbols.String()) entries.SetString("LOCAL_SOONG_JNI_LIBS_SYMBOLS", jniSymbols.String()) } else { var names []string @@ -383,8 +381,6 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", extra.String()+":"+install) } - entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports) - entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", app.logtagsSrcs.Strings()...) }, }, diff --git a/java/apkcerts.go b/java/apkcerts.go new file mode 100644 index 000000000..8aba27b9d --- /dev/null +++ b/java/apkcerts.go @@ -0,0 +1,126 @@ +// Copyright 2015 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" + "fmt" + "slices" + "strings" + + "github.com/google/blueprint" +) + +func init() { + android.InitRegistrationContext.RegisterParallelSingletonType("apkcerts_singleton", apkCertsSingletonFactory) +} + +// Info that should be included into the apkcerts.txt file. +// The info can be provided as either a text file containing a subset of the final apkcerts.txt, +// or as a certificate and name. The text file will be preferred if it exists +type ApkCertInfo struct { + ApkCertsFile android.Path + + Certificate Certificate + Name string + + // True if LOCAL_MODULE_TAGS would contain "tests" in a make build. + // In make this caused the partition in the apkcerts.txt file to be "data" instead of "system" + Test bool +} + +var ApkCertInfoProvider = blueprint.NewProvider[ApkCertInfo]() + +type ApkCertsInfo []ApkCertInfo + +var ApkCertsInfoProvider = blueprint.NewProvider[ApkCertsInfo]() + +func apkCertsSingletonFactory() android.Singleton { + return &apkCertsSingleton{} +} + +type apkCertsSingleton struct{} + +func (a *apkCertsSingleton) GenerateBuildActions(ctx android.SingletonContext) { + apkCerts := []string{} + var apkCertsFiles android.Paths + ctx.VisitAllModuleProxies(func(m android.ModuleProxy) { + commonInfo, ok := android.OtherModuleProvider(ctx, m, android.CommonModuleInfoProvider) + if !ok || commonInfo.SkipAndroidMkProcessing { + return + } + if info, ok := android.OtherModuleProvider(ctx, m, android.HideApexVariantFromMakeProvider); ok && info.HideApexVariantFromMake { + return + } + + partition := commonInfo.PartitionTag + + specifiesPartition := commonInfo.SocSpecific || commonInfo.Vendor || + commonInfo.Proprietary || commonInfo.SystemExtSpecific || commonInfo.ProductSpecific || + commonInfo.DeviceSpecific + + if info, ok := android.OtherModuleProvider(ctx, m, ApkCertsInfoProvider); ok { + for _, certInfo := range info { + if certInfo.ApkCertsFile != nil { + apkCertsFiles = append(apkCertsFiles, certInfo.ApkCertsFile) + } else { + // Partition information of apk-in-apex is not exported to the legacy Make packaging system. + // Hardcode the partition to "system" + apkCerts = append(apkCerts, FormatApkCertsLine(certInfo.Certificate, certInfo.Name, "system")) + } + } + } else if info, ok := android.OtherModuleProvider(ctx, m, ApkCertInfoProvider); ok { + if info.ApkCertsFile != nil { + apkCertsFiles = append(apkCertsFiles, info.ApkCertsFile) + } else { + // From base_rules.mk + if info.Test && partition == "system" && !specifiesPartition { + partition = "data" + } + + apkCerts = append(apkCerts, FormatApkCertsLine(info.Certificate, info.Name, partition)) + } + } + }) + slices.Sort(apkCerts) // sort by name + apkCertsInfoWithoutAppSets := android.PathForOutput(ctx, "apkcerts_singleton", "apkcerts_without_app_sets.txt") + android.WriteFileRule(ctx, apkCertsInfoWithoutAppSets, strings.Join(apkCerts, "\n")) + apkCertsInfo := ApkCertsFile(ctx) + ctx.Build(pctx, android.BuildParams{ + Rule: android.CatAndSortAndUnique, + Description: "combine apkcerts.txt", + Output: apkCertsInfo, + Inputs: append(apkCertsFiles, apkCertsInfoWithoutAppSets), + }) +} + +func (s *apkCertsSingleton) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict("SOONG_APKCERTS_FILE", ApkCertsFile(ctx).String()) +} + +func ApkCertsFile(ctx android.PathContext) android.WritablePath { + return android.PathForOutput(ctx, "apkcerts_singleton", "apkcerts.txt") +} + +func FormatApkCertsLine(cert Certificate, name, partition string) string { + pem := cert.AndroidMkString() + var key string + if cert.Key == nil { + key = "" + } else { + key = cert.Key.String() + } + return fmt.Sprintf(`name="%s" certificate="%s" private_key="%s" partition="%s"`, name, pem, key, partition) +} diff --git a/java/app.go b/java/app.go index 8ed0b46f4..cb1f36fa5 100644 --- a/java/app.go +++ b/java/app.go @@ -78,15 +78,20 @@ type AppInfo struct { Privileged bool OutputFile android.Path InstallApkName string - JacocoReportClassesFile android.Path + JacocoInfo JacocoInfo Certificate Certificate PrivAppAllowlist android.OptionalPath OverriddenManifestPackageName *string ApkCertsFile android.Path + JniLibs []jniLib + JniCoverageOutputs android.Paths + PackedAdditionalOutputs android.Path } var AppInfoProvider = blueprint.NewProvider[*AppInfo]() +type AppInfos []AppInfo + // AndroidManifest.xml merging // package splits @@ -413,11 +418,18 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon TestOnly: true, }) appInfo := &AppInfo{ - Updatable: Bool(a.appProperties.Updatable), - TestHelperApp: true, + Updatable: Bool(a.appProperties.Updatable), + TestHelperApp: true, + JniLibs: a.jniLibs, + JniCoverageOutputs: a.jniCoverageOutputs, } setCommonAppInfo(appInfo, a) android.SetProvider(ctx, AppInfoProvider, appInfo) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: appInfo.Certificate, + Name: appInfo.InstallApkName + ".apk", + Test: true, + }) moduleInfoJSON := ctx.ModuleInfoJSON() moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") @@ -427,11 +439,43 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") } - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: a.appTestHelperAppProperties.Test_suites, + var data []android.DataPath + for _, d := range a.extraOutputFiles { + data = append(data, android.DataPath{SrcPath: d}) + } + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: a.appTestHelperAppProperties.Test_suites, + MainFile: a.outputFile, + MainFileStem: a.installApkName, + MainFileExt: ".apk", + NeedsArchFolder: true, + NonArchData: data, + PerTestcaseDirectory: proptools.Bool(a.appTestHelperAppProperties.Per_testcase_directory), + DisableTestConfig: true, }) } +func (a *AndroidApp) baseSymbolInfo(ctx android.ModuleContext) *cc.SymbolInfo { + return &cc.SymbolInfo{ + Name: a.BaseModuleName(), + ModuleDir: ctx.ModuleDir(), + Uninstallable: a.IsSkipInstall() || !proptools.BoolDefault(a.properties.Installable, true) || a.NoFullInstall(), + } +} + +func (a *AndroidApp) GetJniSymbolInfos(ctx android.ModuleContext, JniSymbolInstallPath android.Path) []*cc.SymbolInfo { + infos := []*cc.SymbolInfo{} + for _, install := range JNISymbolsInstalls(a.jniLibs, JniSymbolInstallPath.String()) { + info := a.baseSymbolInfo(ctx) + info.UnstrippedBinaryPath = install.From + info.ModuleDir = filepath.Dir(install.To) + info.InstalledStem = filepath.Base(install.To) + + infos = append(infos, info) + } + return infos +} + func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkAppSdkVersions(ctx) a.checkEmbedJnis(ctx) @@ -452,15 +496,21 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { EmbeddedJNILibs: embeddedJniLibs, MergedManifestFile: a.mergedManifest, OverriddenManifestPackageName: &overriddenName, + JniLibs: a.jniLibs, + JniCoverageOutputs: a.jniCoverageOutputs, } setCommonAppInfo(appInfo, a) android.SetProvider(ctx, AppInfoProvider, appInfo) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: appInfo.Certificate, + Name: appInfo.InstallApkName + ".apk", + }) a.requiredModuleNames = a.getRequiredModuleNames(ctx) if a.dexer.proguardDictionary.Valid() { android.SetProvider(ctx, ProguardProvider, ProguardInfo{ - ModuleName: ctx.ModuleName(), + ModuleName: android.ModuleNameWithPossibleOverride(ctx), Class: "APPS", ProguardDictionary: a.dexer.proguardDictionary.Path(), ProguardUsageZip: a.dexer.proguardUsageZip.Path(), @@ -836,9 +886,9 @@ func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages andro return jniJarFile } -func (a *AndroidApp) JNISymbolsInstalls(installPath string) android.RuleBuilderInstalls { +func JNISymbolsInstalls(jniLibs []jniLib, installPath string) android.RuleBuilderInstalls { var jniSymbols android.RuleBuilderInstalls - for _, jniLib := range a.jniLibs { + for _, jniLib := range jniLibs { if jniLib.unstrippedFile != nil { jniSymbols = append(jniSymbols, android.RuleBuilderInstall{ From: jniLib.unstrippedFile, @@ -937,12 +987,17 @@ func (a *AndroidApp) createPrivappAllowlist(ctx android.ModuleContext) android.P } func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { + a.jacocoInfo.Class = "APPS" + var apkDeps android.Paths apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) if !apexInfo.IsForPlatform() { a.hideApexVariantFromMake = true } + android.SetProvider(ctx, android.HideApexVariantFromMakeProvider, android.HideApexVariantFromMakeInfo{ + HideApexVariantFromMake: a.hideApexVariantFromMake, + }) a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx) a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex) @@ -1011,7 +1066,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.mergedManifest = a.aapt.mergedManifestFile a.linter.manifest = a.aapt.manifestPath a.linter.resources = a.aapt.resourceFiles - a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() + a.linter.buildModuleReportZip = ctx.Config().HasUnbundledBuildApps() dexJarFile, packageResources, javaInfo := a.dexBuildActions(ctx) @@ -1079,6 +1134,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { bundleFile := android.PathForModuleOut(ctx, "base.zip") BuildBundleModule(ctx, bundleFile, a.exportPackage, jniJarFile, dexJarFile) a.bundleFile = bundleFile + android.SetProvider(ctx, BundleProvider, BundleInfo{Bundle: bundleFile}) allowlist := a.createPrivappAllowlist(ctx) if allowlist != nil { @@ -1115,7 +1171,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } } } - ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...) + a.installedOutputFile = ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...) } ctx.CheckbuildFile(a.outputFile) @@ -1151,6 +1207,14 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.setOutputFiles(ctx) buildComplianceMetadata(ctx) + + if !a.hideApexVariantFromMake && !a.IsHideFromMake() { + if a.embeddedJniLibs { + cc.CopySymbolsAndSetSymbolsInfoProvider(ctx, &cc.SymbolInfos{ + Symbols: a.GetJniSymbolInfos(ctx, a.installPathForJNISymbols), + }) + } + } } func (a *AndroidApp) setOutputFiles(ctx android.ModuleContext) { @@ -1323,7 +1387,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { // Skip dependencies that are only available to APEXes; they are developed with updatability // in mind and don't need manual approval. - if android.OtherModulePointerProviderOrDefault(ctx, to, android.CommonModuleInfoProvider).NotAvailableForPlatform { + if android.OtherModuleProviderOrDefault(ctx, to, android.PlatformAvailabilityInfoProvider).NotAvailableToPlatform { return true } @@ -1458,7 +1522,7 @@ func AndroidAppFactory() android.Module { return } - rroPackageName := a.Name() + "__" + strings.ReplaceAll(characteristics, ",", "_") + "__auto_generated_characteristics_rro" + rroPackageName := AutogeneratedProductCharacteristicsRroModuleName(ctx, a.Name()) rroManifestName := rroPackageName + "_manifest" a.appProperties.ProductCharacteristicsRROPackageName = proptools.StringPtr(rroPackageName) @@ -1511,7 +1575,19 @@ func AndroidAppFactory() android.Module { } func AutogeneratedRroModuleName(ctx android.EarlyModuleContext, moduleName, partition string) string { - return fmt.Sprintf("%s__%s__auto_generated_rro_%s", moduleName, ctx.Config().DeviceProduct(), partition) + // auto_generated_rro is installed to the product or vendor partition and + // are specific to target product. To add the auto_generated_rro to the + // required list of the original app module, the target product name is + // required. + // TODO(b/412526509): Remove the rro dependency from the system partition. + // So, the original system module does not need to know the target product + // name. Instead, add a reverse dependency from the rro to the original + // system module to see if the module exists. + return fmt.Sprintf("%s__%s__auto_generated_rro_%s", moduleName, ctx.Config().Getenv("TARGET_PRODUCT"), partition) +} + +func AutogeneratedProductCharacteristicsRroModuleName(ctx android.EarlyModuleContext, moduleName string) string { + return moduleName + "__" + strings.ReplaceAll(ctx.Config().ProductAAPTCharacteristics(), ",", "_") + "__auto_generated_characteristics_rro" } type createModuleContext interface { @@ -1646,6 +1722,12 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } a.generateAndroidBuildActions(ctx) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: a.Certificate(), + Name: a.InstallApkName() + ".apk", + Test: true, + }) + for _, c := range a.testProperties.Test_options.Tradefed_options { configs = append(configs, c) } @@ -1664,22 +1746,29 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_prefer32_data)...) a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Host_common_data)...) - // Install test deps - if !ctx.Config().KatiEnabled() { - pathInTestCases := android.PathForModuleInstall(ctx, ctx.Module().Name()) - if a.testConfig != nil { - ctx.InstallFile(pathInTestCases, ctx.Module().Name()+".config", a.testConfig) - } - dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml") - if dynamicConfig.Valid() { - ctx.InstallFile(pathInTestCases, ctx.Module().Name()+".dynamic", dynamicConfig.Path()) - } - testDeps := append(a.data, a.extraTestConfigs...) - for _, data := range android.SortedUniquePaths(testDeps) { - dataPath := android.DataPath{SrcPath: data} - ctx.InstallTestData(pathInTestCases, []android.DataPath{dataPath}) - } - } + a.data = android.SortedUniquePaths(a.data) + a.extraTestConfigs = android.SortedUniquePaths(a.extraTestConfigs) + + var testData []android.DataPath + for _, data := range a.data { + dataPath := android.DataPath{SrcPath: data} + testData = append(testData, dataPath) + } + for _, d := range a.extraOutputFiles { + testData = append(testData, android.DataPath{SrcPath: d}) + } + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: a.testProperties.Test_suites, + MainFile: a.outputFile, + MainFileStem: a.installApkName, + MainFileExt: ".apk", + ConfigFile: a.testConfig, + ExtraConfigs: a.extraTestConfigs, + NonArchData: testData, + CompatibilitySupportFiles: a.data, + NeedsArchFolder: true, + PerTestcaseDirectory: proptools.Bool(a.testProperties.Per_testcase_directory), + }) android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ TestcaseRelDataFiles: testcaseRel(a.data), @@ -1714,10 +1803,6 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { moduleInfoJSON.AutoTestConfig = []string{"true"} } moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, a.testProperties.Test_mainline_modules...) - - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: a.testProperties.Test_suites, - }) } func testcaseRel(paths android.Paths) []string { @@ -2047,14 +2132,31 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps boo } } +func (u *usesLibrary) depsFromLibs(ctx android.BottomUpMutatorContext, libDeps []android.Module) { + // 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 { + if dep != nil { + if component, ok := android.OtherModuleProvider(ctx, dep, SdkLibraryComponentDependencyInfoProvider); ok { + if lib := component.OptionalSdkLibraryImplementation; lib != nil { + // Add library as optional if it's one of the optional compatibility libs or it's + // explicitly listed in the optional_uses_libs property. + tag := usesLibReqTag + if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) || + android.InList(*lib, u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) { + tag = usesLibOptTag + } + ctx.AddVariationDependencies(nil, tag, *lib) + } + } + } + } +} + // presentOptionalUsesLibs returns optional_uses_libs after filtering out libraries that don't exist in the source tree. func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string { optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil), func(s string) bool { - exists := ctx.OtherModuleExists(s) - if !exists && !android.InList(ctx.ModuleName(), ctx.Config().BuildWarningBadOptionalUsesLibsAllowlist()) { - fmt.Printf("Warning: Module '%s' depends on non-existing optional_uses_libs '%s'\n", ctx.ModuleName(), s) - } - return exists + return ctx.OtherModuleExists(s) }) return optionalUsesLibs } @@ -2085,7 +2187,7 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext // Skip stub libraries. A dependency on the implementation library has been added earlier, // so it will be added to CLC, but the stub shouldn't be. Stub libraries can be distingushed // from implementation libraries by their name, which is different as it has a suffix. - if comp := javaInfo.SdkLibraryComponentDependencyInfo; comp != nil { + if comp, ok := android.OtherModuleProvider(ctx, m, SdkLibraryComponentDependencyInfoProvider); ok { if impl := comp.OptionalSdkLibraryImplementation; impl != nil && *impl != dep { return } @@ -2180,6 +2282,10 @@ func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile a cmd.FlagWithArg("--missing-optional-uses-library ", lib) } + for _, lib := range ctx.Config().BootJars() { + cmd.FlagWithArg("--bootclasspath-libs ", lib) + } + rule.Build("verify_uses_libraries", "verify <uses-library>") return outputFile } @@ -2206,7 +2312,7 @@ type androidApp interface { Privileged() bool InstallApkName() string OutputFile() android.Path - JacocoReportClassesFile() android.Path + JacocoInfo() JacocoInfo Certificate() Certificate BaseModuleName() string PrivAppAllowlist() android.OptionalPath @@ -2220,11 +2326,13 @@ func setCommonAppInfo(appInfo *AppInfo, m androidApp) { appInfo.Privileged = m.Privileged() appInfo.OutputFile = m.OutputFile() appInfo.InstallApkName = m.InstallApkName() - appInfo.JacocoReportClassesFile = m.JacocoReportClassesFile() + appInfo.JacocoInfo = m.JacocoInfo() appInfo.Certificate = m.Certificate() appInfo.PrivAppAllowlist = m.PrivAppAllowlist() } -type AppInfos []AppInfo +type BundleInfo struct { + Bundle android.Path +} -var AppInfosProvider = blueprint.NewProvider[AppInfos]() +var BundleProvider = blueprint.NewProvider[BundleInfo]() diff --git a/java/app_import.go b/java/app_import.go index 9fb13ba3c..93686a991 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -105,8 +105,6 @@ type AndroidAppImport struct { installPath android.InstallPath hideApexVariantFromMake bool - - provenanceMetaDataFile android.Path } type AndroidAppImportProperties struct { @@ -122,7 +120,7 @@ type AndroidAppImportProperties struct { // Set this flag to true if the prebuilt apk is already signed. The certificate property must not // be set for presigned modules. - Presigned *bool + Presigned proptools.Configurable[bool] `android:"replace_instead_of_append"` // Name of the signing certificate lineage file or filegroup module. Lineage *string `android:"path"` @@ -157,7 +155,7 @@ type AndroidAppImportProperties struct { Relative_install_path *string // Whether the prebuilt apk can be installed without additional processing. Default is false. - Preprocessed *bool + Preprocessed proptools.Configurable[bool] `android:"replace_instead_of_append"` // Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed // JNI libs and dex files. Default is false @@ -289,7 +287,7 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs( ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) { // Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing // with them may invalidate pre-existing signature data. - if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) { + if ctx.InstallInTestcases() && (a.properties.Presigned.GetOrDefault(ctx, false) || a.properties.Preprocessed.GetOrDefault(ctx, false)) { ctx.Build(pctx, android.BuildParams{ Rule: android.Cp, Output: outputPath, @@ -320,7 +318,7 @@ func (a *AndroidAppImport) extractSubApk( // Returns whether this module should have the dex file stored uncompressed in the APK. func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool { - if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) { + if ctx.Config().UnbundledBuild() || a.properties.Preprocessed.GetOrDefault(ctx, false) { return false } @@ -355,11 +353,19 @@ func (a *AndroidAppImport) stripEmbeddedJniLibsUnusedArch( func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.generateAndroidBuildActions(ctx) + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"APPS"} + moduleInfoJSON.SystemSharedLibs = []string{"none"} + appInfo := &AppInfo{ Prebuilt: true, } setCommonAppInfo(appInfo, a) android.SetProvider(ctx, AppInfoProvider, appInfo) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: appInfo.Certificate, + Name: appInfo.InstallApkName + ".apk", + }) } func (a *AndroidAppImport) InstallApkName() string { @@ -380,19 +386,18 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.hideApexVariantFromMake = true } - if Bool(a.properties.Preprocessed) { - if a.properties.Presigned != nil && !*a.properties.Presigned { + if a.properties.Preprocessed.GetOrDefault(ctx, false) { + if !a.properties.Presigned.GetOrDefault(ctx, true) { ctx.ModuleErrorf("Setting preprocessed: true implies presigned: true, so you cannot set presigned to false") } - t := true - a.properties.Presigned = &t + a.properties.Presigned.AppendSimpleValue(true) } numCertPropsSet := 0 if a.properties.Certificate.GetOrDefault(ctx, "") != "" { numCertPropsSet++ } - if Bool(a.properties.Presigned) { + if a.properties.Presigned.GetOrDefault(ctx, false) { numCertPropsSet++ } if Bool(a.properties.Default_dev_cert) { @@ -438,7 +443,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext installDir := android.PathForModuleInstall(ctx, pathFragments...) a.dexpreopter.isApp = true a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk") - a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned) + a.dexpreopter.isPresignedPrebuilt = a.properties.Presigned.GetOrDefault(ctx, false) a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx) a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries(ctx) @@ -476,7 +481,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // Sign or align the package if package has not been preprocessed - if proptools.Bool(a.properties.Preprocessed) { + if a.properties.Preprocessed.GetOrDefault(ctx, false) { validationStamp := a.validatePresignedApk(ctx, srcApk) output := android.PathForModuleOut(ctx, apkFilename) ctx.Build(pctx, android.BuildParams{ @@ -487,7 +492,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext }) a.outputFile = output a.certificate = PresignedCertificate - } else if !Bool(a.properties.Presigned) { + } else if !a.properties.Presigned.GetOrDefault(ctx, false) { // If the certificate property is empty at this point, default_dev_cert must be set to true. // Which makes processMainCert's behavior for the empty cert string WAI. _, _, certificates := collectAppDeps(ctx, a, false, false) @@ -524,7 +529,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext if apexInfo.IsForPlatform() { a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile) artifactPath := android.PathForModuleSrc(ctx, a.properties.Apk.GetOrDefault(ctx, "")) - a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath) + provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath) } providePrebuiltInfo(ctx, @@ -554,7 +559,7 @@ func (a *AndroidAppImport) validatePresignedApk(ctx android.ModuleContext, srcAp if proptools.Bool(a.properties.Skip_preprocessed_apk_checks) { extraArgs = append(extraArgs, "--skip-preprocessed-apk-checks") } - if proptools.Bool(a.properties.Preprocessed) { + if a.properties.Preprocessed.GetOrDefault(ctx, false) { extraArgs = append(extraArgs, "--preprocessed") } @@ -581,18 +586,14 @@ func (a *AndroidAppImport) OutputFile() android.Path { return a.outputFile } -func (a *AndroidAppImport) JacocoReportClassesFile() android.Path { - return nil +func (a *AndroidAppImport) JacocoInfo() JacocoInfo { + return JacocoInfo{} } func (a *AndroidAppImport) Certificate() Certificate { return a.certificate } -func (a *AndroidAppImport) ProvenanceMetaDataFile() android.Path { - return a.provenanceMetaDataFile -} - func (a *AndroidAppImport) PrivAppAllowlist() android.OptionalPath { return android.OptionalPath{} } @@ -788,8 +789,24 @@ func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContex a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: a.testProperties.Test_suites, + var data []android.DataPath + for _, d := range a.data { + data = append(data, android.DataPath{SrcPath: d}) + } + + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: a.testProperties.Test_suites, + MainFile: a.outputFile, + MainFileStem: a.outputFile.Base(), + NeedsArchFolder: true, + Data: data, + CompatibilitySupportFiles: a.data, + }) + + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: a.Certificate(), + Name: a.InstallApkName() + ".apk", + Test: true, }) } diff --git a/java/app_set.go b/java/app_set.go index 6a2c678a8..e7bef6e4f 100644 --- a/java/app_set.go +++ b/java/app_set.go @@ -131,7 +131,7 @@ type prebuiltInfoProps struct { // Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file // with information about whether source or prebuilt of an apex was used during the build. func providePrebuiltInfo(ctx android.ModuleContext, p prebuiltInfoProps) { - info := android.PrebuiltInfo{ + info := android.PrebuiltJsonInfo{ Name: p.baseModuleName, Is_prebuilt: p.isPrebuilt, } @@ -140,7 +140,7 @@ func providePrebuiltInfo(ctx android.ModuleContext, p prebuiltInfoProps) { prebuiltInfoFile := android.PathForModuleSrc(ctx, *p.prebuiltInfo) info.Prebuilt_info_file_path = prebuiltInfoFile.String() } - android.SetProvider(ctx, android.PrebuiltInfoProvider, info) + android.SetProvider(ctx, android.PrebuiltJsonInfoProvider, info) } func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -193,9 +193,13 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) ) android.SetProvider(ctx, AppInfoProvider, &AppInfo{ - AppSet: true, - Privileged: as.Privileged(), - OutputFile: as.OutputFile(), + AppSet: true, + Privileged: as.Privileged(), + OutputFile: as.OutputFile(), + ApkCertsFile: as.apkcertsFile, + PackedAdditionalOutputs: as.packedOutput, + }) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ ApkCertsFile: as.apkcertsFile, }) } diff --git a/java/app_test.go b/java/app_test.go index a8b39b7d1..a33c6b10c 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -15,6 +15,8 @@ package java import ( + "encoding/json" + "errors" "fmt" "path/filepath" "reflect" @@ -3475,9 +3477,6 @@ func TestUsesLibraries(t *testing.T) { prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("runtime-library", "foo", "quuz", "qux", "bar", "fred"), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.BuildWarningBadOptionalUsesLibsAllowlist = []string{"app", "prebuilt"} - }), ).RunTestWithBp(t, bp) app := result.ModuleForTests(t, "app", "android_common") @@ -3532,6 +3531,178 @@ func TestUsesLibraries(t *testing.T) { "--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/app/product_packages.txt") } +func extractContextJson(cmd string) (map[string]interface{}, error) { + var clc map[string]interface{} + for _, flag := range strings.Split(cmd, " ") { + if value, match := strings.CutPrefix(flag, "--context-json='"); match { + value = strings.TrimSuffix(value, "'") + if err := json.Unmarshal([]byte(value), &clc); err != nil { + return nil, err + } + return clc, nil + } + } + return nil, errors.New("--context-json not found") +} + +func TestClassLoaderContext_SdkLibrary(t *testing.T) { + bp := ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_packages: ["foo"], + sdk_version: "current", + uses_libs: ["bar"], + } + + java_sdk_library { + name: "bar", + srcs: ["b.java"], + api_packages: ["bar"], + sdk_version: "current", + } + + android_app { + name: "app", + srcs: ["app.java"], + libs: ["foo.stubs"], + uses_libs: ["foo"], + sdk_version: "current", + } + + android_app { + name: "app2", + srcs: ["app.java"], + libs: ["foo.impl"], + uses_libs: ["foo"], + sdk_version: "current", + } + ` + + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo", "bar"), + ).RunTestWithBp(t, bp) + + { + fooXml := result.ModuleForTests(t, "foo.xml", "android_common").Output("foo.xml") + fooXmlContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooXml) + android.AssertStringDoesContain(t, "", fooXmlContents, `dependency="bar"`) + } + + { + fooImpl := result.ModuleForTests(t, "foo.impl", "android_common") + cmd := fooImpl.Rule("dexpreopt").RuleParams.Command + + clc, err := extractContextJson(cmd) + if err != nil { + t.Error(err) + return + } + + deps := clc["any"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(deps)) + bar := deps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "bar", bar["Name"].(string)) + } + + for _, name := range []string{"app", "app2"} { + app := result.ModuleForTests(t, name, "android_common") + cmd := app.Rule("dexpreopt").RuleParams.Command + + clc, err := extractContextJson(cmd) + if err != nil { + t.Error(err) + return + } + + deps := clc["any"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(deps)) + foo := deps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "foo", foo["Name"].(string)) + fooDeps := foo["Subcontexts"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(fooDeps)) + bar := fooDeps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "bar", bar["Name"].(string)) + } +} + +func TestClassLoaderContext_SdkLibrary2(t *testing.T) { + bp := ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_packages: ["foo"], + sdk_version: "current", + libs: ["bar.impl"], + } + + java_sdk_library { + name: "bar", + srcs: ["b.java"], + api_packages: ["bar"], + sdk_version: "current", + } + + android_app { + name: "app", + srcs: ["app.java"], + libs: ["foo.stubs"], + uses_libs: ["foo"], + sdk_version: "current", + } + ` + + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo", "bar"), + ).RunTestWithBp(t, bp) + + { + fooXml := result.ModuleForTests(t, "foo.xml", "android_common").Output("foo.xml") + fooXmlContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooXml) + android.AssertStringDoesContain(t, "", fooXmlContents, `dependency="bar"`) + } + + { + fooImpl := result.ModuleForTests(t, "foo.impl", "android_common") + cmd := fooImpl.Rule("dexpreopt").RuleParams.Command + + clc, err := extractContextJson(cmd) + if err != nil { + t.Error(err) + return + } + + deps := clc["any"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(deps)) + bar := deps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "bar", bar["Name"].(string)) + } + + { + app := result.ModuleForTests(t, "app", "android_common") + cmd := app.Rule("dexpreopt").RuleParams.Command + + clc, err := extractContextJson(cmd) + if err != nil { + t.Error(err) + return + } + + deps := clc["any"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(deps)) + foo := deps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "foo", foo["Name"].(string)) + fooDeps := foo["Subcontexts"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(fooDeps)) + bar := fooDeps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "bar", bar["Name"].(string)) + } +} + func TestDexpreoptBcp(t *testing.T) { t.Parallel() bp := ` @@ -4578,7 +4749,7 @@ func TestAppFlagsPackages(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 link command expected to pass feature flags arguments", linkInFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) aapt2CompileRule := foo.Rule("android/soong/java.aapt2Compile") @@ -4586,7 +4757,7 @@ func TestAppFlagsPackages(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 compile command expected to pass feature flags arguments", compileFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) } @@ -4658,12 +4829,12 @@ func TestAppFlagsPackagesPropagation(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 link command expected to pass feature flags arguments of flags_packages and that of its static libs", linkInFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) android.AssertStringDoesNotContain(t, "aapt2 link command expected to not pass feature flags arguments of flags_packages of its libs", linkInFlags, - "--feature-flags @out/soong/.intermediates/foo/intermediate.txt", + "--feature-flags @out/soong/.intermediates/foo/aconfig-flags.txt", ) } @@ -4902,6 +5073,7 @@ func TestResourcesWithFlagDirectories(t *testing.T) { "res/flag(!test.package.flag2)/values/bools.xml": nil, "res/flag(test.package.flag1)/values-config/strings_google_services.xml": nil, "res/flags(test.package.flag1)/values/strings.xml": nil, + "res/drawable/flag(test.package.flag1)/qs_flashlight_icon_off.xml": nil, }), ).RunTestWithBp(t, ` android_library { @@ -4940,6 +5112,12 @@ func TestResourcesWithFlagDirectories(t *testing.T) { compileOutputPaths, "out/soong/.intermediates/foo/android_common/aapt2/res/values_strings.(test.package.flag1).arsc.flat", ) + android.AssertStringListContains( + t, + "Expected to generate flag path when it is a subdirectory of resource type subdirectory", + compileOutputPaths, + "out/soong/.intermediates/foo/android_common/aapt2/res/drawable_qs_flashlight_icon_off.(test.package.flag1).xml.flat", + ) } func TestAutogeneratedStaticRro(t *testing.T) { diff --git a/java/base.go b/java/base.go index 8aa0109d0..7d56522b9 100644 --- a/java/base.go +++ b/java/base.go @@ -15,7 +15,6 @@ package java import ( - "encoding/gob" "fmt" "path/filepath" "reflect" @@ -33,6 +32,8 @@ import ( "android/soong/java/config" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // This file contains the definition and the implementation of the base module that most // source-based Java module structs embed. @@ -94,12 +95,18 @@ type CommonProperties struct { // See kotlinc's `-language-version` flag. Kotlin_lang_version *string + // Whether this target supports compilation with the kotlin-incremental-client. + Kotlin_incremental *bool + // list of java libraries that will be in the classpath Libs []string `android:"arch_variant"` // list of java libraries that will be compiled into the resulting jar Static_libs proptools.Configurable[[]string] `android:"arch_variant"` + // List of Kotlin libraries whose `internal` members are accessible to this library + Associates []string `android:"arch_variant"` + // manifest file to be included in resulting jar Manifest *string `android:"path"` @@ -229,6 +236,11 @@ type CommonProperties struct { // If true, then only the headers are built and not the implementation jar. Headers_only *bool + // If specified, this is used for this library's header jar, rather than generating it. This + // should only be used if the library adds nothing new to the header jars vs the provided path. + // For example, this could be used if the module only adds implementation code. + Header_jar_override string `android:"path,arch_variant"` + // A list of files or dependencies to make available to the build sandbox. This is // useful if source files are symlinks, the targets of the symlinks must be listed here. // Note that currently not all actions implemented by android_apps are sandboxed, so you @@ -251,6 +263,9 @@ type CommonProperties struct { // If true, the "Ravenizer" tool will remove all Mockito and DexMaker // classes from the output jar. Strip_mockito *bool + + // Extra arguments passed to Ravenizer + Flags []string } // Contributing api surface of the stub module. Is not visible to bp modules, and should @@ -505,11 +520,12 @@ type Module struct { dexJarFile OptionalDexJarPath // output file containing uninstrumented classes that will be instrumented by jacoco - jacocoReportClassesFile android.Path + jacocoInfo JacocoInfo // output file of the module, which may be a classes jar or a dex jar - outputFile android.Path - extraOutputFiles android.Paths + outputFile android.Path + installedOutputFile android.Path + extraOutputFiles android.Paths exportAidlIncludeDirs android.Paths ignoredAidlPermissionList android.Paths @@ -867,6 +883,17 @@ func (j *Module) staticLibs(ctx android.BaseModuleContext) []string { return j.properties.Static_libs.GetOrDefault(ctx, nil) } +func (j *Module) incrementalKotlin(config android.Config) bool { + incremental := proptools.BoolDefault( + j.properties.Kotlin_incremental, config.PartialCompileFlags().Enable_inc_kotlin) + nonIncrementalFlags := []string{"-Xmulti-platform", "-Xexpect-actual-classes"} + for _, flag := range nonIncrementalFlags { + incremental = incremental && !slices.Contains(j.properties.Kotlincflags, flag) + } + + return incremental +} + func (j *Module) deps(ctx android.BottomUpMutatorContext) { if ctx.Device() { j.linter.deps(ctx) @@ -892,24 +919,7 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { traceRefs := j.dexProperties.Optimize.Trace_references_from.GetOrDefault(ctx, []string{}) ctx.AddVariationDependencies(nil, traceReferencesTag, traceRefs...) - // 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 { - if dep != nil { - if component, ok := dep.(SdkLibraryComponentDependency); ok { - if lib := component.OptionalSdkLibraryImplementation(); lib != nil { - // Add library as optional if it's one of the optional compatibility libs or it's - // explicitly listed in the optional_uses_libs property. - tag := usesLibReqTag - if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) || - android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) { - tag = usesLibOptTag - } - ctx.AddVariationDependencies(nil, tag, *lib) - } - } - } - } + j.usesLibrary.depsFromLibs(ctx, libDeps) ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...) ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, j.properties.Kotlin_plugins...) @@ -943,10 +953,17 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent") } + incremental := j.incrementalKotlin(ctx.Config()) if j.useCompose(ctx) { - ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, + if incremental { + ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), composeEmbeddablePluginTag, + "kotlin-compose-compiler-embeddable-plugin") + } + ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), composePluginTag, "kotlin-compose-compiler-plugin") } + + j.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } func hasSrcExt(srcs []string, ext string) bool { @@ -1152,14 +1169,6 @@ func (j *Module) collectJavacFlags( return flags } -func (j *Module) AddJSONData(d *map[string]interface{}) { - (&j.ModuleBase).AddJSONData(d) - (*d)["Java"] = map[string]interface{}{ - "SourceExtensions": j.sourceExtensions, - } - -} - func (j *Module) addGeneratedSrcJars(path android.Path) { j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path) } @@ -1284,10 +1293,10 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars - localHeaderJars, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, + localHeaderJars, _, preJarjarHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraCombinedJars) - combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine", false) + combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, preJarjarHeaderJarFile, jarName, "turbine", false) if jarjared { localHeaderJars = android.Paths{combinedHeaderJarFile} transitiveStaticLibsHeaderJars = nil @@ -1301,6 +1310,9 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath return nil } j.headerJarFile = combinedHeaderJarFile + if deps.headerJarOverride.Valid() { + j.headerJarFile = deps.headerJarOverride.Path() + } if len(localHeaderJars) > 0 { ctx.CheckbuildFile(localHeaderJars...) @@ -1312,6 +1324,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath j.outputFile = j.headerJarFile return &JavaInfo{ HeaderJars: android.PathsIfNonNil(j.headerJarFile), + LocalHeaderJarsPreJarjar: android.PathsIfNonNil(preJarjarHeaderJarFile), LocalHeaderJars: localHeaderJars, TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars), TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8, @@ -1323,6 +1336,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath StubsLinkType: j.stubsLinkType, AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles, SdkVersion: j.SdkVersion(ctx), + OverrideMinSdkVersion: j.overridableProperties.Min_sdk_version, + Installable: BoolDefault(j.properties.Installable, true), } } @@ -1367,23 +1382,73 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath kotlincFlags = append(kotlincFlags, "-no-jdk") } + var kotlincPluginFlags []string for _, plugin := range deps.kotlinPlugins { - kotlincFlags = append(kotlincFlags, "-Xplugin="+plugin.String()) + kotlincPluginFlags = append(kotlincPluginFlags, "-Xplugin="+plugin.String()) + } + if len(kotlincPluginFlags) > 0 { + // optimization. + ctx.Variable(pctx, "kotlincPluginFlags", strings.Join(kotlincPluginFlags, " ")) + flags.kotlincPluginFlags += "$kotlincPluginFlags" } flags.kotlincDeps = append(flags.kotlincDeps, deps.kotlinPlugins...) + if deps.composePlugin.Valid() { + flags.composePluginFlag = "-Xplugin=" + deps.composePlugin.String() + ctx.Variable(pctx, "composePluginFlag", flags.composePluginFlag) + flags.kotlincDeps = append(flags.kotlincDeps, deps.composePlugin.Path()) + } + if deps.composeEmbeddablePlugin.Valid() { + flags.composeEmbeddablePluginFlag = "-Xplugin=" + deps.composeEmbeddablePlugin.String() + ctx.Variable(pctx, "composeEmbeddablePluginFlag", flags.composeEmbeddablePluginFlag) + flags.kotlincDeps = append(flags.kotlincDeps, deps.composeEmbeddablePlugin.Path()) + } + + // TODO(b/403236545): Remove this once the Kotlin compiler version is >= 2.2.0. + if j.useCompose(ctx) { + kotlincFlags = append(kotlincFlags, "-P", "plugin:androidx.compose.compiler.plugins.kotlin:featureFlag=+OptimizeNonSkippingGroups") + } + if len(kotlincFlags) > 0 { + // Flags with `-J` as a prefix are meant to be passed to java directly. + // When running the kotlin-incremental-client, flags are first parsed by a bash + // script that eagerly takes all the leading arguments that start with `-J` and feeds + // them to java. Any `-J` arguments that occur elsewhere (i.e. after a non-J argument) + // fail to pass through to java as expected. + slices.SortStableFunc(kotlincFlags, func(a, b string) int { + aHasPrefix := strings.HasPrefix(a, "-J") + bHasPrefix := strings.HasPrefix(b, "-J") + + // If only a has the prefix, it should come before b + if aHasPrefix && !bHasPrefix { + return -1 + } else if bHasPrefix && !aHasPrefix { + return 1 + } + return 0 // Otherwise maintain their order + }) // optimization. ctx.Variable(pctx, "kotlincFlags", strings.Join(kotlincFlags, " ")) flags.kotlincFlags += "$kotlincFlags" } + incrementalKotlin := j.incrementalKotlin(ctx.Config()) + // Collect common .kt files for AIDEGen j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, kotlinCommonSrcFiles.Strings()...) flags.kotlincClasspath = append(flags.kotlincClasspath, flags.bootClasspath...) flags.kotlincClasspath = append(flags.kotlincClasspath, flags.classpath...) + kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) + kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) + + kotlinCompileData := KotlinCompileData{ + diffFile: kotlinJar.ReplaceExtension(ctx, "source_diff"), + pcStateFileNew: kotlinJar.ReplaceExtension(ctx, "pc_state.new"), + pcStateFilePrior: kotlinJar.ReplaceExtension(ctx, "pc_state"), + } + if len(flags.processorPath) > 0 { // Use kapt for annotation processing kaptSrcJar := android.PathForModuleOut(ctx, "kapt", "kapt-sources.jar") @@ -1396,9 +1461,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath flags.processors = nil } - kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) - kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) - j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) + j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags, kotlinCompileData, incrementalKotlin) if ctx.Failed() { return nil } @@ -1421,6 +1484,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath var localHeaderJars android.Paths var shardingHeaderJars android.Paths var repackagedHeaderJarFile android.Path + var combinedHeaderJarFile android.Path if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine { if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 { enableSharding = true @@ -1432,9 +1496,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } extraJars := slices.Clone(kotlinHeaderJars) extraJars = append(extraJars, extraCombinedJars...) - var combinedHeaderJarFile android.Path - localHeaderJars, combinedHeaderJarFile = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars) - shardingHeaderJars = localHeaderJars + localHeaderJars, shardingHeaderJars, combinedHeaderJarFile = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars) var jarjared bool j.headerJarFile, jarjared = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine", false) @@ -1464,6 +1526,24 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath break } } + + // turbine is disabled when API generating APs are present, in which case, + // we would want to process annotations before moving to incremental javac + var genAnnoSrcJar android.Path + if ctx.Device() && ctx.Config().PartialCompileFlags().Enable_inc_javac && disableTurbine { + srcJarsForTurbine := slices.Clone(srcJars) + if len(flags.processorPath) > 0 { + genAnnoSrcJar, _ = j.generateJavaAnnotations(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, nil) + flags.processorPath = nil + flags.processors = nil + srcJarsForTurbine = append(srcJarsForTurbine, genAnnoSrcJar) + } + // turbine was disabled, lets run it now + turbineExtraJars := slices.Clone(kotlinHeaderJars) + turbineExtraJars = append(turbineExtraJars, extraCombinedJars...) + _, shardingHeaderJars, _ = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJarsForTurbine, deps, flags, jarName, turbineExtraJars) + } + var extraJarDeps android.Paths if Bool(j.properties.Errorprone.Enabled) { // If error-prone is enabled, enable errorprone flags on the regular @@ -1486,7 +1566,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath errorprone := android.PathForModuleOut(ctx, "errorprone", jarName) errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar") - transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil, + transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, false, errorproneFlags, nil, "errorprone", "errorprone") extraJarDeps = append(extraJarDeps, errorprone) @@ -1503,7 +1583,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath shardSrcs = android.ShardPaths(uniqueJavaFiles, shardSize) for idx, shardSrc := range shardSrcs { classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc, - nil, flags, extraJarDeps) + nil, nil, flags, extraJarDeps, nil) classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx)) localImplementationJars = append(localImplementationJars, classes) } @@ -1516,13 +1596,13 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath shardSrcJarsList := android.ShardPaths(srcJars, shardSize/5) for idx, shardSrcJars := range shardSrcJarsList { classes := j.compileJavaClasses(ctx, jarName, startIdx+idx, - nil, shardSrcJars, flags, extraJarDeps) + nil, shardSrcJars, nil, flags, extraJarDeps, nil) classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx)) localImplementationJars = append(localImplementationJars, classes) } } } else { - classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps) + classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, shardingHeaderJars, flags, extraJarDeps, genAnnoSrcJar) classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac") localImplementationJars = append(localImplementationJars, classes) } @@ -1685,10 +1765,12 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath if j.ravenizer.enabled { ravenizerInput := outputFile ravenizerOutput := android.PathForModuleOut(ctx, "ravenizer", "", jarName) - ravenizerArgs := "" + + ravenizerArgs := j.properties.Ravenizer.Flags if proptools.Bool(j.properties.Ravenizer.Strip_mockito) { - ravenizerArgs = "--strip-mockito" + ravenizerArgs = append(ravenizerArgs, "--strip-mockito") } + TransformRavenizer(ctx, ravenizerOutput, ravenizerInput, ravenizerArgs) outputFile = ravenizerOutput localImplementationJars = android.Paths{ravenizerOutput} @@ -1835,7 +1917,11 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // If r8/d8 provides a profile that matches the optimized dex, use that for dexpreopt. if dexArtProfileOutput != nil { - j.dexpreopter.SetRewrittenProfile(dexArtProfileOutput) + if concretePtr, ok := dexArtProfileOutput.(*android.OutputPath); ok { + if concretePtr != nil { + j.dexpreopter.SetRewrittenProfile(dexArtProfileOutput) + } + } } // merge dex jar with resources if necessary @@ -1864,11 +1950,13 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) // Dexpreopting - libName := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()) - if j.SdkLibraryName() != nil && strings.HasSuffix(ctx.ModuleName(), ".impl") { - libName = strings.TrimSuffix(libName, ".impl") + if dexArtProfileOutput != nil { + libName := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()) + if j.SdkLibraryName() != nil && strings.HasSuffix(ctx.ModuleName(), ".impl") { + libName = strings.TrimSuffix(libName, ".impl") + } + j.dexpreopt(ctx, libName, dexOutputFile) } - j.dexpreopt(ctx, libName, dexOutputFile) outputFile = dexOutputFile @@ -1905,7 +1993,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" j.linter.compile_data = android.PathsForModuleSrc(ctx, j.properties.Compile_data) - if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() { + if !apexInfo.IsForPlatform() && ctx.Config().HasUnbundledBuildApps() { j.linter.buildModuleReportZip = true } j.linter.lint(ctx) @@ -1925,11 +2013,16 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource j.outputFile = outputFile.WithoutRel() + if deps.headerJarOverride.Valid() { + j.headerJarFile = deps.headerJarOverride.Path() + } return &JavaInfo{ - HeaderJars: android.PathsIfNonNil(j.headerJarFile), - RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile), + HeaderJars: android.PathsIfNonNil(j.headerJarFile), + LocalHeaderJarsPreJarjar: android.PathsIfNonNil(combinedHeaderJarFile), + RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile), LocalHeaderJars: localHeaderJars, + KotlinHeaderJars: kotlinHeaderJars, TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars), TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars, TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars, @@ -1946,11 +2039,13 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath ExportedPlugins: j.exportedPluginJars, ExportedPluginClasses: j.exportedPluginClasses, ExportedPluginDisableTurbine: j.exportedDisableTurbine, - JacocoReportClassesFile: j.jacocoReportClassesFile, + JacocoInfo: j.jacocoInfo, StubsLinkType: j.stubsLinkType, AconfigIntermediateCacheOutputPaths: j.aconfigCacheFiles, SdkVersion: j.SdkVersion(ctx), OutputFile: j.outputFile, + OverrideMinSdkVersion: j.overridableProperties.Min_sdk_version, + Installable: BoolDefault(j.properties.Installable, true), } } @@ -2018,7 +2113,7 @@ func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags { } func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, idx int, - srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.Path { + srcFiles, srcJars, localHeaderJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths, genAnnoSrcJar android.Path) android.Path { kzipName := pathtools.ReplaceExtension(jarName, "kzip") annoSrcJar := android.PathForModuleOut(ctx, "javac", "anno.srcjar") @@ -2029,7 +2124,13 @@ func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, i } classes := android.PathForModuleOut(ctx, "javac", jarName) - TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps) + // enable incremental javac when corresponding flags are enabled and + // header jars are present + if ctx.Config().PartialCompileFlags().Enable_inc_javac && len(localHeaderJars) > 0 { + TransformJavaToClassesInc(ctx, classes, srcFiles, srcJars, localHeaderJars, annoSrcJar, flags, extraJarDeps, genAnnoSrcJar) + } else { + TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps) + } if ctx.Config().EmitXrefRules() && ctx.Module() == ctx.PrimaryModule() { extractionFile := android.PathForModuleOut(ctx, kzipName) @@ -2044,6 +2145,20 @@ func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, i return classes } +func (j *Module) generateJavaAnnotations(ctx android.ModuleContext, jarName string, idx int, + srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) (android.Path, android.Path) { + + annoSrcJar := android.PathForModuleOut(ctx, "javac-apt", "anno.srcjar") + if idx >= 0 { + annoSrcJar = android.PathForModuleOut(ctx, "javac-apt", "anno-"+strconv.Itoa(idx)+".srcjar") + jarName += strconv.Itoa(idx) + } + + classes := android.PathForModuleOut(ctx, "javac-apt", jarName) + GenerateJavaAnnotations(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps) + return annoSrcJar, classes +} + // Check for invalid kotlinc flags. Only use this for flags explicitly passed by the user, // since some of these flags may be used internally. func CheckKotlincFlags(ctx android.ModuleContext, flags []string) { @@ -2073,7 +2188,21 @@ func CheckKotlincFlags(ctx android.ModuleContext, flags []string) { func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths, deps deps, flags javaBuilderFlags, jarName string, - extraJars android.Paths) (localHeaderJars android.Paths, combinedHeaderJar android.Path) { + extraJars android.Paths) (localHeaderJars, localHeaderJarsForSharding android.Paths, combinedHeaderJar android.Path) { + + if deps.headerJarOverride.Valid() { + // If we are sharding, we need the pre-jarjar override path; localHeaderJars always + // needs the jarjared version. + localHeaderJars = append(android.Paths{deps.headerJarOverride.Path()}, extraJars...) + var headerJar android.Path + if deps.headerJarOverridePreJarjar.Valid() { + headerJar = deps.headerJarOverridePreJarjar.Path() + } else { + headerJar = deps.headerJarOverride.Path() + } + localHeaderJarsForSharding = append(android.Paths{headerJar}, extraJars...) + return localHeaderJars, localHeaderJarsForSharding, deps.headerJarOverride.Path() + } if len(srcFiles) > 0 || len(srcJars) > 0 { // Compile java sources into turbine.jar. @@ -2089,13 +2218,14 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars depSet := depset.New(depset.PREORDER, localHeaderJars, deps.transitiveStaticLibsHeaderJars) jars := depSet.ToList() + var combinedHeaderJarOutputPath android.WritablePath // we cannot skip the combine step for now if there is only one jar // since we have to strip META-INF/TRANSITIVE dir from turbine.jar - combinedHeaderJarOutputPath := android.PathForModuleOut(ctx, "turbine-combined", jarName) + combinedHeaderJarOutputPath = android.PathForModuleOut(ctx, "turbine-combined", jarName) TransformJarsToJar(ctx, combinedHeaderJarOutputPath, "for turbine", jars, android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"}) - return localHeaderJars, combinedHeaderJarOutputPath + return localHeaderJars, localHeaderJars, combinedHeaderJarOutputPath } func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, @@ -2106,7 +2236,12 @@ func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, jacocoInstrumentJar(ctx, instrumentedJar, jacocoReportClassesFile, classesJar, specs) - j.jacocoReportClassesFile = jacocoReportClassesFile + j.jacocoInfo.ReportClassesFile = jacocoReportClassesFile + j.jacocoInfo.ModuleName = android.ModuleNameWithPossibleOverride(ctx) + // Allow overriding the class before instrument() is called + if j.jacocoInfo.Class == "" { + j.jacocoInfo.Class = "JAVA_LIBRARIES" + } return instrumentedJar } @@ -2251,8 +2386,8 @@ func (j *Module) Stem() string { return j.stem } -func (j *Module) JacocoReportClassesFile() android.Path { - return j.jacocoReportClassesFile +func (j *Module) JacocoInfo() JacocoInfo { + return j.jacocoInfo } func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) { @@ -2463,6 +2598,15 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + case headerJarOverrideTag: + if dep.HeaderJars == nil { + ctx.ModuleErrorf("%s does not provide header jars", otherName) + } else if len(dep.HeaderJars) > 1 { + ctx.ModuleErrorf("%s provides too many header jars", otherName) + } else { + deps.headerJarOverride = android.OptionalPathForPath(dep.HeaderJars[0]) + deps.headerJarOverridePreJarjar = android.OptionalPathForPath(dep.LocalHeaderJarsPreJarjar[0]) + } case java9LibTag: deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) transitiveJava9ClasspathHeaderJars = append(transitiveJava9ClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) @@ -2519,6 +2663,18 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } else { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } + case composeEmbeddablePluginTag: + if _, ok := android.OtherModuleProvider(ctx, module, KotlinPluginInfoProvider); ok { + deps.composeEmbeddablePlugin = android.OptionalPathForPath(dep.ImplementationAndResourcesJars[0]) + } else { + ctx.PropertyErrorf("kotlin_plugins", "%q is not a kotlin_plugin module", otherName) + } + case composePluginTag: + if _, ok := android.OtherModuleProvider(ctx, module, KotlinPluginInfoProvider); ok { + deps.composePlugin = android.OptionalPathForPath(dep.ImplementationAndResourcesJars[0]) + } else { + ctx.PropertyErrorf("kotlin_plugins", "%q is not a kotlin_plugin module", otherName) + } case kotlinPluginTag: if _, ok := android.OtherModuleProvider(ctx, module, KotlinPluginInfoProvider); ok { deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...) @@ -2556,6 +2712,8 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case staticLibTag: deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) } + } else if dep, ok := android.OtherModuleProvider(ctx, module, DroidStubsInfoProvider); ok { + deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigProtoFiles...) } else { switch tag { case bootClasspathTag: @@ -2645,6 +2803,7 @@ const ( RenameUseExclude ) +// @auto-generate: gob type JarJarProviderData struct { // Mapping of class names: original --> renamed. If the value is "", the class will be // renamed by the next rdep that has the jarjar_prefix attribute (or this module if it has @@ -2669,12 +2828,11 @@ var overridableJarJarPrefix = "com.android.internal.hidden_from_bootclasspath" func init() { android.SetJarJarPrefixHandler(mergeJarJarPrefixes) - - gob.Register(BaseJarJarProviderData{}) } // BaseJarJarProviderData contains information that will propagate across dependencies regardless of // whether they are java modules or not. +// @auto-generate: gob type BaseJarJarProviderData struct { JarJarProviderData JarJarProviderData } @@ -2849,6 +3007,15 @@ func (this Module) GetDebugString() string { // Merge the jarjar rules we inherit from our dependencies, any that have been added directly to // us, and if it's been set, apply the jarjar_prefix property to rename them. func (module *Module) collectJarJarRules(ctx android.ModuleContext) *JarJarProviderData { + + // Stop collect jarjar_prefix jarjar rules if the module has test sdk scope. + // If a module uses test API scope, which means in its source code and static dependencies + // it could only use API exposed through the test surface. So it should not apply the jarjar + // rules set by any bootclass path jar + if ctx.Config().ReleaseJarjarFlagsInFramework() && module.SdkVersion(ctx).Kind == android.SdkTest { + return nil + } + // Gather repackage information from deps result := collectDirectDepsProviders(ctx) diff --git a/java/base_gob_enc.go b/java/base_gob_enc.go new file mode 100644 index 000000000..a99c98670 --- /dev/null +++ b/java/base_gob_enc.go @@ -0,0 +1,89 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package java + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + JarJarProviderDataGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(JarJarProviderData) }) + BaseJarJarProviderDataGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(BaseJarJarProviderData) }) +} + +func (r JarJarProviderData) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Rename))); err != nil { + return err + } + for k, v := range r.Rename { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeString(buf, v); err != nil { + return err + } + } + return err +} + +func (r *JarJarProviderData) Decode(buf *bytes.Reader) error { + var err error + + var val1 int32 + err = gobtools.DecodeSimple[int32](buf, &val1) + if err != nil { + return err + } + if val1 > 0 { + r.Rename = make(map[string]string, val1) + for val2 := 0; val2 < int(val1); val2++ { + var k string + var v string + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + err = gobtools.DecodeString(buf, &v) + if err != nil { + return err + } + r.Rename[k] = v + } + } + + return err +} + +var JarJarProviderDataGobRegId int16 + +func (r JarJarProviderData) GetTypeId() int16 { + return JarJarProviderDataGobRegId +} + +func (r BaseJarJarProviderData) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.JarJarProviderData.Encode(buf); err != nil { + return err + } + return err +} + +func (r *BaseJarJarProviderData) Decode(buf *bytes.Reader) error { + var err error + + if err = r.JarJarProviderData.Decode(buf); err != nil { + return err + } + + return err +} + +var BaseJarJarProviderDataGobRegId int16 + +func (r BaseJarJarProviderData) GetTypeId() int16 { + return BaseJarJarProviderDataGobRegId +} diff --git a/java/boot_jars.go b/java/boot_jars.go index 3c3bd550c..75a35f13c 100644 --- a/java/boot_jars.go +++ b/java/boot_jars.go @@ -21,11 +21,18 @@ 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.ConfigurableEvaluatorContext, module android.Module) bool { - if !module.Enabled(ctx) { - return false +func isActiveModule(ctx android.ModuleContext, module android.ModuleOrProxy) bool { + if android.EqualModules(ctx.Module(), module) { + if !ctx.Module().Enabled(ctx) { + return false + } + } else { + info := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) + if !info.Enabled { + return false + } } - return android.IsModulePreferred(module) + return android.IsModulePreferredProxy(ctx, module) } // buildRuleForBootJarsPackageCheck generates the build rule to perform the boot jars package diff --git a/java/bootclasspath.go b/java/bootclasspath.go index 98fb417d0..6c82d330c 100644 --- a/java/bootclasspath.go +++ b/java/bootclasspath.go @@ -71,8 +71,8 @@ func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex st // gatherFragments collects fragments that are direct dependencies of this module, as well as // any fragments in apexes via the dependency on the apex. It returns a list of the fragment // modules and map from apex name to the fragment in that apex. -func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[string]android.Module) { - var fragments []android.Module +func gatherFragments(ctx android.BaseModuleContext) ([]android.ModuleProxy, map[string]android.ModuleProxy) { + var fragments []android.ModuleProxy type fragmentInApex struct { module string @@ -82,7 +82,7 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin var fragmentsInApexes []fragmentInApex // Find any direct dependencies, as well as a list of the modules in apexes. - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { t := ctx.OtherModuleDependencyTag(module) if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment { if bcpTag.moduleInApex != "" { @@ -93,13 +93,13 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin } }) - fragmentsMap := make(map[string]android.Module) + fragmentsMap := make(map[string]android.ModuleProxy) for _, fragmentInApex := range fragmentsInApexes { - var found android.Module + var found android.ModuleProxy // Find a desired module in an apex. - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { t := ctx.OtherModuleDependencyTag(child) - if parent == ctx.Module() { + if android.EqualModules(parent, ctx.Module()) { if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment && ctx.OtherModuleName(child) == fragmentInApex.apex { // This is the dependency from this module to the apex, recurse into it. return true @@ -112,7 +112,7 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin return false } else if android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) == fragmentInApex.module { // This is the desired module inside the apex. - if found != nil && child != found { + if !found.IsNil() && child != found { panic(fmt.Errorf("found two conflicting modules %q in apex %q: %s and %s", fragmentInApex.module, fragmentInApex.apex, found, child)) } @@ -120,7 +120,7 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin } return false }) - if found != nil { + if !found.IsNil() { if existing, exists := fragmentsMap[fragmentInApex.apex]; exists { ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", fragmentInApex.apex, fragmentInApex.module, existing) } else { @@ -137,9 +137,10 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin // gatherApexModulePairDepsWithTag returns the list of dependencies with the supplied tag that was // added by addDependencyOntoApexModulePair. -func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType bootclasspathDependencyTagType) ([]android.Module, map[android.Module]string) { - var modules []android.Module - modulesToApex := make(map[android.Module]string) +func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, + tagType bootclasspathDependencyTagType) ([]android.ModuleProxy, map[android.ModuleProxy]string) { + var modules []android.ModuleProxy + modulesToApex := make(map[android.ModuleProxy]string) type moduleInApex struct { module string @@ -148,7 +149,7 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot var modulesInApexes []moduleInApex - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { t := ctx.OtherModuleDependencyTag(module) if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == tagType { if bcpTag.moduleInApex != "" { @@ -160,10 +161,10 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot }) for _, moduleInApex := range modulesInApexes { - var found android.Module - ctx.WalkDeps(func(child, parent android.Module) bool { + var found android.ModuleProxy + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { t := ctx.OtherModuleDependencyTag(child) - if parent == ctx.Module() { + if android.EqualModules(parent, ctx.Module()) { if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == tagType && ctx.OtherModuleName(child) == moduleInApex.apex { // recurse into the apex return true @@ -177,7 +178,7 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot } else if IsBootclasspathFragmentContentDepTag(t) { return false } else if android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) == moduleInApex.module { - if found != nil && child != found { + if !found.IsNil() && child != found { panic(fmt.Errorf("found two conflicting modules %q in apex %q: %s and %s", moduleInApex.module, moduleInApex.apex, found, child)) } @@ -185,7 +186,7 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot } return false }) - if found != nil { + if !found.IsNil() { modules = append(modules, found) if existing, exists := modulesToApex[found]; exists && existing != moduleInApex.apex { ctx.ModuleErrorf("module %s is in two apexes, %s and %s", moduleInApex.module, existing, moduleInApex.apex) diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index a09416dc4..4505a40c4 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -41,7 +41,14 @@ func registerBootclasspathFragmentBuildComponents(ctx android.RegistrationContex ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootclasspathFragmentFactory) } -type BootclasspathFragmentInfo struct{} +type BootclasspathFragmentInfo struct { + ImageName *string + Contents []string + ApiStubLibs []string + CorePlatformApiStubLibs []string + Fragments []ApexVariantReference + ProfilePathOnHost android.Path +} var BootclasspathFragmentInfoProvider = blueprint.NewProvider[BootclasspathFragmentInfo]() @@ -73,10 +80,10 @@ func (b bootclasspathFragmentContentDependencyTag) ReplaceSourceWithPrebuilt() b // SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if // they were specified using java_boot_libs or java_sdk_libs. -func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType { +func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(ctx android.ModuleContext, child android.ModuleProxy) android.SdkMemberType { // If the module is a java_sdk_library then treat it as if it was specified in the java_sdk_libs // property, otherwise treat if it was specified in the java_boot_libs property. - if javaSdkLibrarySdkMemberType.IsInstance(child) { + if javaSdkLibrarySdkMemberType.IsInstance(ctx, child) { return javaSdkLibrarySdkMemberType } @@ -267,7 +274,8 @@ type commonBootclasspathFragment interface { // Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the // module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a // versioned sdk. - produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput + produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.ModuleProxy, fragments []android.ModuleProxy, + input HiddenAPIFlagInput) *HiddenAPIOutput // getProfilePath returns the path to the boot image profile. getProfilePath() android.Path @@ -392,7 +400,7 @@ type BootclasspathFragmentApexContentInfo struct { // DexBootJarPathForContentModule returns the path to the dex boot jar for specified module. // // The dex boot jar is one which has had hidden API encoding performed on it. -func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) (android.Path, error) { +func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.ModuleOrProxy) (android.Path, error) { // A bootclasspath_fragment cannot use a prebuilt library so Name() will return the base name // without a prebuilt_ prefix so is safe to use as the key for the contentModuleDexJarPaths. name := module.Name() @@ -530,9 +538,13 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // Generate classpaths.proto config b.generateClasspathProtoBuildActions(ctx) + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"FAKE"} + moduleInfoJSON.SystemSharedLibs = []string{"none"} + // Gather the bootclasspath fragment's contents. - var contents []android.Module - ctx.VisitDirectDeps(func(module android.Module) { + var contents []android.ModuleProxy + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(module) if IsBootclasspathFragmentContentDepTag(tag) { contents = append(contents, module) @@ -544,7 +556,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // Perform hidden API processing. hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments) - if android.IsModulePrebuilt(ctx.Module()) { + if android.IsModulePrebuilt(ctx, ctx.Module()) { b.profilePath = ctx.Module().(*PrebuiltBootclasspathFragmentModule).produceBootImageProfile(ctx) } else { b.profilePath = b.produceBootImageProfileFromSource(ctx, contents, hiddenAPIOutput.EncodedBootDexFilesByModule) @@ -562,14 +574,21 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo b.HideFromMake() } - android.SetProvider(ctx, BootclasspathFragmentInfoProvider, BootclasspathFragmentInfo{}) + android.SetProvider(ctx, BootclasspathFragmentInfoProvider, BootclasspathFragmentInfo{ + ImageName: b.properties.Image_name, + Contents: b.properties.Contents.GetOrDefault(ctx, nil), + ApiStubLibs: b.properties.Api.Stub_libs.GetOrDefault(ctx, nil), + CorePlatformApiStubLibs: b.properties.Core_platform_api.Stub_libs.GetOrDefault(ctx, nil), + Fragments: b.properties.Fragments, + ProfilePathOnHost: b.profilePath, + }) } // getProfileProviderApex returns the name of the apex that provides a boot image profile, or an // empty string if this module should not provide a boot image profile. func (b *BootclasspathFragmentModule) getProfileProviderApex(ctx android.BaseModuleContext) string { // Only use the profile from the module that is preferred. - if !isActiveModule(ctx, ctx.Module()) { + if !android.IsModulePreferredProxy(ctx, ctx.Module()) { return "" } @@ -646,7 +665,7 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) // TODO(b/202896428): Add better way to handle this. _, unknown = android.RemoveFromList("android.car-module", unknown) if isApexVariant(ctx) && len(unknown) > 0 { - if android.IsModulePrebuilt(ctx.Module()) { + if android.IsModulePrebuilt(ctx, ctx.Module()) { // prebuilt bcpf. the validation of this will be done at the top-level apex providerClasspathFragmentValidationInfoProvider(ctx, unknown) } else if !disableSourceApexVariant(ctx) && android.IsModulePreferred(ctx.Module()) { @@ -676,7 +695,8 @@ func providerClasspathFragmentValidationInfoProvider(ctx android.ModuleContext, } // generateHiddenAPIBuildActions generates all the hidden API related build rules. -func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput { +func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.ModuleProxy, + fragments []android.ModuleProxy) *HiddenAPIOutput { // Create hidden API input structure. input := b.createHiddenAPIFlagInput(ctx, contents, fragments) @@ -720,7 +740,8 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. // createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived // from the properties on this module and its dependencies. -func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput { +func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.ModuleProxy, + fragments []android.ModuleProxy) HiddenAPIFlagInput { // Merge the HiddenAPIInfo from all the fragment dependencies. dependencyHiddenApiInfo := newHiddenAPIInfo() dependencyHiddenApiInfo.mergeFromFragmentDeps(ctx, fragments) @@ -752,7 +773,7 @@ func (b *BootclasspathFragmentModule) isTestFragment() bool { // generateHiddenApiFlagRules generates rules to generate hidden API flags and compute the signature // patterns file. -func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput, bootDexInfoByModule bootDexInfoByModule, suffix string) HiddenAPIFlagOutput { +func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.ModuleContext, contents []android.ModuleProxy, input HiddenAPIFlagInput, bootDexInfoByModule bootDexInfoByModule, suffix string) HiddenAPIFlagOutput { // Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the // paths to the created files. flagOutput := hiddenAPIFlagRulesForBootclasspathFragment(ctx, bootDexInfoByModule, contents, input, suffix) @@ -781,7 +802,8 @@ func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.Mod // produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files) // for the fragment as well as encoding the flags in the boot dex jars. -func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { +func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.ModuleProxy, + fragments []android.ModuleProxy, input HiddenAPIFlagInput) *HiddenAPIOutput { // Gather information about the boot dex files for the boot libraries provided by this fragment. bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents) @@ -805,11 +827,12 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC // Filter the contents list to remove any modules that do not support the target build release. // The current build release supports all the modules. - contentsForSdkSnapshot := []android.Module{} + contentsForSdkSnapshot := []android.ModuleProxy{} for _, module := range contents { // If the module has a min_sdk_version that is higher than the target build release then it will // not work on the target build release and so must not be included in the sdk snapshot. - minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, module) + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) + minApiLevel := android.MinApiLevelForSdkSnapshot(commonInfo) if minApiLevel.GreaterThan(targetApiLevel) { continue } @@ -843,7 +866,8 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC } // produceBootImageProfileFromSource builds the boot image profile from the source if it is required. -func (b *BootclasspathFragmentModule) produceBootImageProfileFromSource(ctx android.ModuleContext, contents []android.Module, modules bootDexJarByModule) android.WritablePath { +func (b *BootclasspathFragmentModule) produceBootImageProfileFromSource(ctx android.ModuleContext, + contents []android.ModuleProxy, modules bootDexJarByModule) android.WritablePath { apex := b.getProfileProviderApex(ctx) if apex == "" { return nil @@ -897,8 +921,8 @@ func (b *bootclasspathFragmentMemberType) AddDependencies(ctx android.SdkDepende ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (b *bootclasspathFragmentMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*BootclasspathFragmentModule) +func (b *bootclasspathFragmentMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + _, ok := android.OtherModuleProvider(ctx, module, BootclasspathFragmentInfoProvider) return ok } @@ -958,15 +982,15 @@ type bootclasspathFragmentSdkMemberProperties struct { Filtered_flags_path android.OptionalPath `supported_build_releases:"Tiramisu+"` } -func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - module := variant.(*BootclasspathFragmentModule) +func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + mctx := ctx.SdkModuleContext() + module, _ := android.OtherModuleProvider(mctx, variant, BootclasspathFragmentInfoProvider) - b.Image_name = module.properties.Image_name - b.Contents = module.properties.Contents.GetOrDefault(ctx.SdkModuleContext(), nil) + b.Image_name = module.ImageName + b.Contents = module.Contents // Get the hidden API information from the module. - mctx := ctx.SdkModuleContext() - hiddenAPIInfo, _ := android.OtherModuleProvider(mctx, module, HiddenAPIInfoForSdkProvider) + hiddenAPIInfo, _ := android.OtherModuleProvider(mctx, variant, HiddenAPIInfoForSdkProvider) b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory // Copy all the generated file paths. @@ -982,11 +1006,11 @@ func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx andro b.Filtered_flags_path = android.OptionalPathForPath(hiddenAPIInfo.FilteredFlagsPath) // Copy stub_libs properties. - b.Stub_libs = module.properties.Api.Stub_libs.GetOrDefault(mctx, nil) - b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs.GetOrDefault(mctx, nil) + b.Stub_libs = module.ApiStubLibs + b.Core_platform_stub_libs = module.CorePlatformApiStubLibs // Copy fragment properties. - b.Fragments = module.properties.Fragments + b.Fragments = module.Fragments } func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { @@ -1108,7 +1132,8 @@ func (module *PrebuiltBootclasspathFragmentModule) Name() string { } // produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified. -func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { +func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, + contents []android.ModuleProxy, fragments []android.ModuleProxy, input HiddenAPIFlagInput) *HiddenAPIOutput { pathForOptionalSrc := func(src *string, defaultPath android.Path) android.Path { if src == nil { return defaultPath diff --git a/java/builder.go b/java/builder.go index dff0032d8..3251dfd9c 100644 --- a/java/builder.go +++ b/java/builder.go @@ -20,6 +20,7 @@ package java import ( "path/filepath" + "slices" "strconv" "strings" @@ -33,13 +34,101 @@ import ( var ( pctx = android.NewPackageContext("android/soong/java") + // Unzips java src files from supplied jars into a directory provided. + extractSrcJars = pctx.AndroidStaticRule("javac-extract-srcJars", + blueprint.RuleParams{ + Command: `rm -rf "$extractDir" && mkdir -p "$extractDir" && ${config.ZipSyncCmd} -d "$extractDir" -l "$out" -f "*.java" $jars`, + CommandDeps: []string{ + "${config.ZipSyncCmd}", + }, + }, "extractDir", "jars", + ) + + // Removes all outputs of inc-javac rule + javacIncClean = pctx.AndroidStaticRule("javac-inc-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "${srcJarDir}" "${outDir}" "${annoDir}" "${annoSrcJar}" "${builtOut}"`, + }, "srcJarDir", "outDir", "annoDir", "annoSrcJar", "builtOut", + ) + + // Incremental javac rule + // The idea of this rule is to make javac incremental, i.e. use the input and + // output of previous javac execution to reduce the src lists. + // This rule is very similar to the normal javac rule with a few differences: + // * Does not unzip srcJars in the rule + // * Does not remove the temp directories containing classes/generated sources + // * Saves the states of a bunch of input params, when javac executes successfully. + // * Runs additional tools on the output to prepare for next iteration + javacInc, javacIncRE = pctx.MultiCommandRemoteStaticRules("javac-inc", + blueprint.RuleParams{ + Command: `rm -rf "$annoSrcJar.tmp" "$out.tmp" && ` + + `mkdir -p "$annoDir" && ` + + `if [ -s $out.rsp ] && [ -s $srcJarList ] ; then ` + + `echo >> $out.rsp; fi && ` + + `cat $srcJarList >> $out.rsp && ` + + `if [ -s $genAnnoSrcJarList ] ; then ` + + `echo >> $out.rsp && cat $genAnnoSrcJarList >> $out.rsp; fi && ` + + `${config.IncrementalJavacInputCmd} ` + + `--srcs $out.rsp --classDir $outDir --deps $javacDeps --javacTarget $out --srcDepsProto $out.proto --localHeaderJars $localHeaderJars && ` + + `mkdir -p "$outDir" && ` + + `(if [ -s $out.inc.rsp ] ; then ` + + `${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` + + `${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` + + `$processorpath $processor $javacFlags $bootClasspath $classpath ` + + `-source $javaVersion -target $javaVersion ` + + `-d $outDir -s $annoDir @$out.inc.rsp ; fi ) && ` + + `cat $out.rem.rsp | xargs rm -f && ` + + `$annoSrcJarTemplate${config.SoongZipCmd} -jar -o $annoSrcJar.tmp -C $annoDir -D $annoDir && ` + + `$zipTemplate${config.SoongZipCmd} -jar -o $out.tmp -C $outDir -D $outDir && ` + + `if ! cmp -s "$out.tmp" "$out"; then mv "$out.tmp" "$out"; fi && ` + + `if ! cmp -s "$annoSrcJar.tmp" "$annoSrcJar"; then mv "$annoSrcJar.tmp" "$annoSrcJar"; fi && ` + + `if [ -f "$out.input.pc_state.new" ]; then mv "$out.input.pc_state.new" "$out.input.pc_state" && ` + + `rm -rf $out.input.pc_state.new; fi && ` + + `if [ -f "$out.deps.pc_state.new" ]; then mv "$out.deps.pc_state.new" "$out.deps.pc_state" && ` + + `rm -rf $out.deps.pc_state.new; fi && ` + + `if [ -f "$out.headers.pc_state.new" ]; then mv "$out.headers.pc_state.new" "$out.headers.pc_state" && ` + + `rm -rf $out.headers.pc_state.new; fi && ` + + `if [ -f $out.rsp ] && [ -f $out ]; then ` + + `${config.DependencyMapperJavacCmd} --src-path $out.rsp --jar-path $out --dependency-map-path $out.proto; fi`, + CommandDeps: []string{ + "${config.DependencyMapperJavacCmd}", + "${config.IncrementalJavacInputCmd}", + "${config.JavacCmd}", + "${config.ZipSyncCmd}", + }, + CommandOrderOnly: []string{"${config.SoongJavacWrapper}"}, + Restat: true, + Rspfile: "$out.rsp", + RspfileContent: "$in", + }, map[string]*remoteexec.REParams{ + "$javaTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "lang": "java", "compiler": "javac"}, + ExecStrategy: "${config.REJavacExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$out.tmp"}, + ExecStrategy: "${config.REJavacExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$annoSrcJarTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$annoDir"}, + OutputFiles: []string{"$annoSrcJar.tmp"}, + ExecStrategy: "${config.REJavacExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJarList", "genAnnoSrcJarList", + "outDir", "annoDir", "annoSrcJar", "javaVersion", "javacDeps", "localHeaderJars"}, nil) + // Compiling java is not conducive to proper dependency tracking. The path-matches-class-name // requirement leads to unpredictable generated source file names, and a single .java file // will get compiled into multiple .class files if it contains inner classes. To work around // this, all java rules write into separate directories and then are combined into a .jar file // (if the rule produces .class files) or a .srcjar file (if the rule produces .java files). // .srcjar files are unzipped into a temporary directory when compiled with javac. - // TODO(b/143658984): goma can't handle the --system argument to javac. javac, javacRE = pctx.MultiCommandRemoteStaticRules("javac", blueprint.RuleParams{ Command: `rm -rf "$outDir" "$annoDir" "$annoSrcJar.tmp" "$srcJarDir" "$out.tmp" && ` + @@ -312,10 +401,12 @@ var ( blueprint.RuleParams{ Command: `${aconfig} dump-cache --dedup --format=protobuf ` + `--out ${out} ` + - `${flags_path} ` + + `@$out.rsp ` + `${filter_args} `, - CommandDeps: []string{"${aconfig}"}, - Description: "aconfig_bool", + CommandDeps: []string{"${aconfig}"}, + Description: "aconfig_bool", + Rspfile: "$out.rsp", + RspfileContent: "${flags_path}", }, "flags_path", "filter_args") generateMetalavaRevertAnnotationsRule = pctx.AndroidStaticRule("generateMetalavaRevertAnnotationsRule", @@ -374,9 +465,12 @@ type javaBuilderFlags struct { errorProneExtraJavacFlags string errorProneProcessorPath classpath - kotlincFlags string - kotlincClasspath classpath - kotlincDeps android.Paths + kotlincFlags string + kotlincPluginFlags string + composePluginFlag string + composeEmbeddablePluginFlag string + kotlincClasspath classpath + kotlincDeps android.Paths proto android.ProtoFlags } @@ -387,6 +481,14 @@ func DefaultJavaBuilderFlags() javaBuilderFlags { } } +func TransformJavaToClassesInc(ctx android.ModuleContext, outputFile android.WritablePath, + srcFiles, srcJars, headerJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths, genAnnoSrcJar android.Path) { + + // Compile java sources into .class files + desc := "javac-inc" + transformJavaToClassesInc(ctx, outputFile, srcFiles, srcJars, headerJars, annoSrcJar, flags, deps, "javac", desc, genAnnoSrcJar) +} + func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) { @@ -395,8 +497,18 @@ func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab if shardIdx >= 0 { desc += strconv.Itoa(shardIdx) } + transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, false, flags, deps, "javac", desc) +} +func GenerateJavaAnnotations(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int, + srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) { + + // Generate src files from Java Annotations. + desc := "javac-apt" + if shardIdx >= 0 { + desc += strconv.Itoa(shardIdx) + } - transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, flags, deps, "javac", desc) + transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, true, flags, deps, "javac-apt", desc) } // Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars @@ -588,6 +700,153 @@ func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.Wr }) } +// Similar to transformJavaToClasses, with additional tweaks to make java +// compilation work incrementally (i.e. work with a smaller subset of src java files +// rather than the full set) +func transformJavaToClassesInc(ctx android.ModuleContext, outputFile android.WritablePath, + srcFiles, srcJars, shardingHeaderJars android.Paths, annoSrcJar android.WritablePath, + flags javaBuilderFlags, deps android.Paths, intermediatesDir, desc string, genAnnoSrcJar android.Path) { + + javacClasspath := flags.classpath + + var bootClasspath string + if flags.javaVersion.usesJavaModules() { + var systemModuleDeps android.Paths + bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device()) + deps = append(deps, systemModuleDeps...) + javacClasspath = append(flags.java9Classpath, javacClasspath...) + } else { + deps = append(deps, flags.bootClasspath...) + if len(flags.bootClasspath) == 0 && ctx.Device() { + // explicitly specify -bootclasspath "" if the bootclasspath is empty to + // ensure java does not fall back to the default bootclasspath. + bootClasspath = `-bootclasspath ""` + } else { + bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath") + } + } + + deps = append(deps, flags.processorPath...) + deps = append(deps, javacClasspath...) + + // The file containing dependencies of the current module + // Any change in them may warrant changes in the incremental compilation + // source set. + javacDeps := outputFile.ReplaceExtension(ctx, "jar.deps.rsp") + android.WriteFileRule(ctx, javacDeps, strings.Join(deps.Strings(), "\n")) + deps = append(deps, javacDeps) + + // Add localHeader Jars in classpath, they are required for incremental compilation. + // These are conspicuously not added to javacDeps file, as a change in them + // does not warrant full re-compilation. + javacClasspath = append(classpath(slices.Clone(shardingHeaderJars)), javacClasspath...) + deps = append(deps, shardingHeaderJars...) + shardingHeaderRsp := outputFile.ReplaceExtension(ctx, "jar.headers.rsp") + android.WriteFileRule(ctx, shardingHeaderRsp, strings.Join(shardingHeaderJars.Strings(), "\n")) + deps = append(deps, shardingHeaderRsp) + + // Doing this now, sow that they are not added to javacDeps file + deps = append(deps, srcJars...) + + classpathArg := javacClasspath.FormJavaClassPath("-classpath") + + // Keep the command line under the MAX_ARG_STRLEN limit by putting the classpath argument into an rsp file + // if it is too long. + const classpathLimit = 64 * 1024 + if len(classpathArg) > classpathLimit { + classpathRspFile := outputFile.ReplaceExtension(ctx, "classpath") + android.WriteFileRule(ctx, classpathRspFile, classpathArg) + deps = append(deps, classpathRspFile) + classpathArg = "@" + classpathRspFile.String() + } + + processor := "-proc:none" + if len(flags.processors) > 0 { + processor = "-processor " + strings.Join(flags.processors, ",") + } + + srcJarDir := "srcjars" + outDir := "classes" + annoDir := "anno" + srcJarList := android.PathForModuleOut(ctx, intermediatesDir, srcJarDir, "list") + deps = append(deps, srcJarList) + + ctx.Build(pctx, android.BuildParams{ + Rule: extractSrcJars, + Description: "javacExtractSrcJars", + Inputs: srcJars, + Output: srcJarList, + Args: map[string]string{ + "extractDir": android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(), + "jars": strings.Join(srcJars.Strings(), " "), + }, + }) + + genAnnoSrcJarList := android.PathForModuleOut(ctx, intermediatesDir, annoDir, "list") + deps = append(deps, genAnnoSrcJarList) + var jars string + if genAnnoSrcJar != nil { + jars = genAnnoSrcJar.String() + } else { + jars = "" + } + ctx.Build(pctx, android.BuildParams{ + Rule: extractSrcJars, + Description: "javacExtractAnnoSrcJar", + Input: genAnnoSrcJar, + Output: genAnnoSrcJarList, + Args: map[string]string{ + "extractDir": android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(), + "jars": jars, + }, + }) + + rule := javacInc + ctx.Build(pctx, android.BuildParams{ + Rule: rule, + Description: desc, + Output: outputFile, + ImplicitOutput: annoSrcJar, + Inputs: srcFiles, + Implicits: deps, + Args: map[string]string{ + "javacFlags": flags.javacFlags, + "bootClasspath": bootClasspath, + "classpath": classpathArg, + "processorpath": flags.processorPath.FormJavaClassPath("-processorpath"), + "processor": processor, + "srcJarList": srcJarList.String(), + "genAnnoSrcJarList": genAnnoSrcJarList.String(), + "outDir": android.PathForModuleOut(ctx, intermediatesDir, outDir).String(), + "annoDir": android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(), + "annoSrcJar": annoSrcJar.String(), + "javaVersion": flags.javaVersion.String(), + "javacDeps": javacDeps.String(), + "localHeaderJars": shardingHeaderRsp.String(), + }, + }) + + // The Phony Clean rule allows javac to move from incremental to full, without + // re-analysis by removing all the outputs of javac, triggering all rules + // that generate them. + cleanPhonyPath := android.PathForModuleOut(ctx, "dex", outputFile.String()+"-partialcompileclean").OutputPath + // Generate the rule for partial compile clean. + ctx.Build(pctx, android.BuildParams{ + Rule: javacIncClean, + Description: "javacIncClean", + Output: cleanPhonyPath, + Args: map[string]string{ + "srcJarDir": android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(), + "outDir": android.PathForModuleOut(ctx, intermediatesDir, outDir).String(), + "annoDir": android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(), + "annoSrcJar": annoSrcJar.String(), + "builtOut": outputFile.String(), + }, + PhonyOutput: true, + }) + ctx.Phony("partialcompileclean", cleanPhonyPath) +} + // transformJavaToClasses takes source files and converts them to a jar containing .class files. // srcFiles is a list of paths to sources, srcJars is a list of paths to jar files that contain // sources. flags contains various command line flags to be passed to the compiler. @@ -597,8 +856,11 @@ func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.Wr // be printed at build time. The stem argument provides the file name of the output jar, and // suffix will be appended to various intermediate files and directories to avoid collisions when // this function is called twice in the same module directory. +// +// This method can also be used to only process Annotations, without completely +// compiling java sources. func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, - shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, + shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, onlyGenerateAnnotations bool, flags javaBuilderFlags, deps android.Paths, intermediatesDir, desc string) { @@ -640,7 +902,11 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab processor := "-proc:none" if len(flags.processors) > 0 { - processor = "-processor " + strings.Join(flags.processors, ",") + if onlyGenerateAnnotations { + processor = "-proc:only -processor " + strings.Join(flags.processors, ",") + } else { + processor = "-processor " + strings.Join(flags.processors, ",") + } } srcJarDir := "srcjars" @@ -852,14 +1118,14 @@ func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePat } func TransformRavenizer(ctx android.ModuleContext, outputFile android.WritablePath, - inputFile android.Path, ravenizerArgs string) { + inputFile android.Path, ravenizerArgs []string) { ctx.Build(pctx, android.BuildParams{ Rule: ravenizer, Description: "ravenizer", Output: outputFile, Input: inputFile, Args: map[string]string{ - "ravenizerArgs": ravenizerArgs, + "ravenizerArgs": strings.Join(ravenizerArgs, " "), }, }) } @@ -920,6 +1186,10 @@ func (x *classpath) FormRepeatedClassPath(optName string) []string { return flags } +func (x *classpath) FirstUniquePaths() classpath { + return classpath(android.FirstUniquePaths(x.Paths())) +} + // Convert a classpath to an android.Paths func (x *classpath) Paths() android.Paths { return append(android.Paths(nil), (*x)...) diff --git a/java/classpath_element.go b/java/classpath_element.go index 4af277012..263a5f116 100644 --- a/java/classpath_element.go +++ b/java/classpath_element.go @@ -28,7 +28,7 @@ import ( // ClasspathElement represents a component that contributes to a classpath. That can be // either a java module or a classpath fragment module. type ClasspathElement interface { - Module() android.Module + Module() android.ModuleProxy String() string } @@ -36,11 +36,11 @@ type ClasspathElements []ClasspathElement // ClasspathFragmentElement is a ClasspathElement that encapsulates a classpath fragment module. type ClasspathFragmentElement struct { - Fragment android.Module - Contents []android.Module + Fragment android.ModuleProxy + Contents []android.ModuleProxy } -func (b *ClasspathFragmentElement) Module() android.Module { +func (b *ClasspathFragmentElement) Module() android.ModuleProxy { return b.Fragment } @@ -56,10 +56,10 @@ var _ ClasspathElement = (*ClasspathFragmentElement)(nil) // ClasspathLibraryElement is a ClasspathElement that encapsulates a java library. type ClasspathLibraryElement struct { - Library android.Module + Library android.ModuleProxy } -func (b *ClasspathLibraryElement) Module() android.Module { +func (b *ClasspathLibraryElement) Module() android.ModuleProxy { return b.Library } @@ -118,10 +118,10 @@ type ClasspathElementContext interface { // ClasspathFragmentElement(art-bootclasspath-fragment, [core-oj, core-libart]), // ClasspathLibraryElement(framework), // ClasspathLibraryElement(ext), -func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module, - libraryToApex map[android.Module]string, apexNameToFragment map[string]android.Module) ClasspathElements { +func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.ModuleProxy, fragments []android.ModuleProxy, + libraryToApex map[android.ModuleProxy]string, apexNameToFragment map[string]android.ModuleProxy) ClasspathElements { - fragmentToElement := map[android.Module]*ClasspathFragmentElement{} + fragmentToElement := map[android.ModuleProxy]*ClasspathFragmentElement{} elements := []ClasspathElement{} var currentElement ClasspathElement @@ -130,11 +130,11 @@ skipLibrary: for _, library := range libraries { var element ClasspathElement if libraryApex, ok := libraryToApex[library]; ok { - var fragment android.Module + var fragment android.ModuleProxy // Make sure that the library is in only one fragment of the classpath. if f, ok := apexNameToFragment[libraryApex]; ok { - if fragment == nil { + if fragment.IsNil() { // This is the first fragment so just save it away. fragment = f } else if f != fragment { @@ -148,7 +148,7 @@ skipLibrary: // There is no fragment associated with the library's apex. } - if fragment == nil { + if fragment.IsNil() { ctx.ModuleErrorf("library %s is from apexes %s which have no corresponding fragment in %s", library, []string{libraryApex}, fragments) // Skip over this library entirely as otherwise the resulting classpath elements would @@ -184,7 +184,7 @@ skipLibrary: // including the library. fragmentElement := &ClasspathFragmentElement{ Fragment: fragment, - Contents: []android.Module{library}, + Contents: []android.ModuleProxy{library}, } // Store it away so we can detect when attempting to create another element for the same diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go index 88a8fb80a..6b9dc194a 100644 --- a/java/classpath_fragment.go +++ b/java/classpath_fragment.go @@ -104,17 +104,14 @@ type classpathJar struct { func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string { set := map[string]struct{}{} for _, name := range contents { - dep := ctx.GetDirectDepWithTag(name, tag) - if dep == nil && ctx.Config().AllowMissingDependencies() { + dep := ctx.GetDirectDepProxyWithTag(name, tag) + if dep.IsNil() && ctx.Config().AllowMissingDependencies() { // Ignore apex boot jars from dexpreopt if it does not exist, and missing deps are allowed. continue } - set[ModuleStemForDeapexing(dep)] = struct{}{} - if m, ok := dep.(ModuleWithStem); ok { - set[m.Stem()] = struct{}{} - } else { - ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name) - } + info := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider) + set[ModuleStemForDeapexing(ctx, dep)] = struct{}{} + set[info.Stem] = struct{}{} } return android.SortedKeys(set) } @@ -129,12 +126,15 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars classpath: classpathType, path: paths[i], } - ctx.VisitDirectDepsIf(func(m android.Module) bool { - return m.Name() == configuredJars.Jar(i) - }, func(m android.Module) { - if s, ok := m.(*SdkLibrary); ok { - minSdkVersion := s.MinSdkVersion(ctx) - maxSdkVersion := s.MaxSdkVersion(ctx) + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { + if m.Name() != configuredJars.Jar(i) { + return + } + if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok { + info := android.OtherModuleProviderOrDefault(ctx, m, JavaInfoProvider) + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + minSdkVersion := *commonInfo.MinSdkVersion.ApiLevel + maxSdkVersion := info.MaxSdkVersion // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current" if minSdkVersion.Specified() { if minSdkVersion.IsCurrent() { diff --git a/java/config/config.go b/java/config/config.go index fdb8d7886..3538aa155 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -160,6 +160,9 @@ func init() { pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file") pctx.HostBinToolVariable("FindInputDeltaCmd", "find_input_delta") + pctx.HostBinToolVariable("IncrementalJavacInputCmd", "incremental_javac_input") + pctx.HostBinToolVariable("IncrementalDexInputCmd", "incremental_dex_input") + pctx.HostBinToolVariable("DependencyMapperJavacCmd", "dependency-mapper") pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh") pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh") diff --git a/java/config/kotlin.go b/java/config/kotlin.go index ffb025d9c..bbf580253 100644 --- a/java/config/kotlin.go +++ b/java/config/kotlin.go @@ -26,6 +26,7 @@ var ( ) func init() { + pctx.HostBinToolVariable("KotlinIncrementalClientBinary", "kotlin-incremental-client") pctx.SourcePathVariable("KotlincCmd", "external/kotlinc/bin/kotlinc") pctx.SourcePathVariable("KotlinCompilerJar", "external/kotlinc/lib/kotlin-compiler.jar") pctx.SourcePathVariable("KotlinPreloaderJar", "external/kotlinc/lib/kotlin-preloader.jar") @@ -33,6 +34,7 @@ func init() { pctx.SourcePathVariable("KotlinScriptRuntimeJar", "external/kotlinc/lib/kotlin-script-runtime.jar") pctx.SourcePathVariable("KotlinTrove4jJar", "external/kotlinc/lib/trove4j.jar") pctx.SourcePathVariable("KotlinKaptJar", "external/kotlinc/lib/kotlin-annotation-processing.jar") + pctx.SourcePathVariable("KotlinKaptEmbeddableJar", "external/kotlinc/lib/kotlin-annotation-processing-embeddable-2.1.10.jar") pctx.SourcePathVariable("KotlinAnnotationJar", "external/kotlinc/lib/annotations-13.0.jar") pctx.SourcePathVariable("KotlinStdlibJar", KotlinStdlibJar) pctx.SourcePathVariable("KotlinAbiGenPluginJar", "external/kotlinc/lib/jvm-abi-gen.jar") diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 04def3e28..283d04598 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -102,7 +102,7 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont var transitiveImplementationJars []depset.DepSet[android.Path] var transitiveResourceJars []depset.DepSet[android.Path] - ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(deviceHostConverterDepTag, func(m android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { d.headerJars = append(d.headerJars, dep.HeaderJars...) d.implementationJars = append(d.implementationJars, dep.ImplementationJars...) @@ -158,6 +158,21 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont setExtraJavaInfo(ctx, d, javaInfo) android.SetProvider(ctx, JavaInfoProvider, javaInfo) + if ctx.Os() != android.Windows { // Make does not support Windows Java modules + if d.combinedImplementationJar != nil { + ctx.CheckbuildFile(d.combinedImplementationJar) + } + if d.combinedHeaderJar != nil { + ctx.CheckbuildFile(d.combinedHeaderJar) + } + } + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if d.combinedImplementationJar != nil { + moduleInfoJSON.ClassesJar = []string{d.combinedImplementationJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (d *DeviceHostConverter) HeaderJars() android.Paths { @@ -184,10 +199,6 @@ func (d *DeviceHostConverter) ClassLoaderContexts() dexpreopt.ClassLoaderContext return nil } -func (d *DeviceHostConverter) JacocoReportClassesFile() android.Path { - return nil -} - func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData { return android.AndroidMkData{ Class: "JAVA_LIBRARIES", diff --git a/java/dex.go b/java/dex.go index e3058e9bf..fa38d6131 100644 --- a/java/dex.go +++ b/java/dex.go @@ -15,6 +15,8 @@ package java import ( + "fmt" + "path/filepath" "strconv" "strings" @@ -25,6 +27,10 @@ import ( "android/soong/remoteexec" ) +func init() { + pctx.HostBinToolVariable("symbols_map", "symbols_map") +} + type DexProperties struct { // If set to true, compile dex regardless of installable. Defaults to false. Compile_dex *bool @@ -80,9 +86,10 @@ type DexProperties struct { Shrink *bool // If true, optimize bytecode. Defaults to false. - Optimize *bool + Optimize proptools.Configurable[bool] `android:"replace_instead_of_append"` - // If true, obfuscate bytecode. Defaults to false. + // If true, obfuscate bytecode by renaming packages, classes, and members. + // Defaults to false. Obfuscate *bool // If true, do not use the flag files generated by aapt that automatically keep @@ -135,6 +142,11 @@ type DexProperties struct { // TODO(b/212737576): Handle this implicitly using bottom-up deps mutation and implicit // creation of a proxy `.impl` library. Trace_references_from proptools.Configurable[[]string] `android:"arch_variant"` + + // Add libraries using `--classpath` instead of `--libs`, to allow overrides. This + // should normally not be used, but can be necessary when running R8 on the boot + // classpath itself. + Import_libraries_as_classpath *bool } // Keep the data uncompressed. We always need uncompressed dex for execution, @@ -182,10 +194,125 @@ func (d *DexProperties) optimizedResourceShrinkingEnabled(ctx android.ModuleCont return d.resourceShrinkingEnabled(ctx) && BoolDefault(d.Optimize.Optimized_shrink_resources, ctx.Config().UseOptimizedResourceShrinkingByDefault()) } -func (d *dexer) optimizeOrObfuscateEnabled(ctx android.EarlyModuleContext) bool { - return d.effectiveOptimizeEnabled(ctx) && (proptools.Bool(d.dexProperties.Optimize.Optimize) || proptools.Bool(d.dexProperties.Optimize.Obfuscate)) +func (d *dexer) optimizeOrObfuscateEnabled(ctx android.ModuleContext) bool { + return d.effectiveOptimizeEnabled(ctx) && (d.dexProperties.Optimize.Optimize.GetOrDefault(ctx, false) || proptools.Bool(d.dexProperties.Optimize.Obfuscate)) } +// Removes all outputs of d8Inc rule +var d8IncClean = pctx.AndroidStaticRule("d8Inc-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "${outDir}" "${builtOut}" "${d8Deps}"`, + }, "outDir", "d8Flags", "d8Deps", "zipFlags", "mergeZipsFlags", "builtOut", +) + +var d8Inc, d8IncRE = pctx.MultiCommandRemoteStaticRules("d8Inc", + blueprint.RuleParams{ + Command: `mkdir -p "$outDir" "$outDir/packages" && ` + + `${config.IncrementalDexInputCmd} ` + + `--classesJar $in --dexTarget $out --deps $d8Deps --outputDir $outDir --packageOutputDir $outDir/packages && ` + + `$d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in --packages $out.rsp --mod-packages $out.inc.rsp --package-output $outDir/packages && ` + + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` + + `if [ -f "$out.input.pc_state.new" ]; then mv "$out.input.pc_state.new" "$out.input.pc_state" && ` + + `rm -rf $out.input.pc_state.new; fi && ` + + `if [ -f "$out.deps.pc_state.new" ]; then mv "$out.deps.pc_state.new" "$out.deps.pc_state" && ` + + `rm -rf $out.deps.pc_state.new; fi && ` + + `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar"`, + CommandDeps: []string{ + "${config.IncrementalDexInputCmd}", + "${config.D8Cmd}", + "${config.SoongZipCmd}", + "${config.MergeZipsCmd}", + }, + }, map[string]*remoteexec.REParams{ + "$d8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "d8"}, + Inputs: []string{"${config.D8Jar}"}, + ExecStrategy: "${config.RED8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$outDir/classes.dex.jar"}, + ExecStrategy: "${config.RED8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "d8Flags", "zipFlags", "mergeZipsFlags", "d8Deps"}, nil) + +// Include all of the args for d8IncR8, so that we can generate the partialcompileclean target's build using the same list. +var d8IncR8Clean = pctx.AndroidStaticRule("d8Incr8-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "${outDir}" "${outDict}" "${outConfig}" "${outUsage}" "${outUsageZip}" "${outUsageDir}" ` + + `"${resourcesOutput}" "${outR8ArtProfile}" ${builtOut} ${d8Deps}`, + }, "outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", "builtOut", + "d8Flags", "d8Deps", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile", "implicits", +) + +var d8IncR8, d8IncR8RE = pctx.MultiCommandRemoteStaticRules("d8Incr8", + blueprint.RuleParams{ + Command: `mkdir -p "$outDir" "$outDir/packages" && ` + + `rm -f "$outDict" && rm -f "$outConfig" && rm -rf "${outUsageDir}" && ` + + `mkdir -p $$(dirname ${outUsage}) && ` + + `if [ -n "$${SOONG_USE_PARTIAL_COMPILE}" ]; then ` + + ` for f in "${outConfig}" "${outDict}" "${outUsage}" "${resourcesOutput}"; do ` + + ` test -n "$${f}" && test ! -f "$${f}" && mkdir -p "$$(dirname "$${f}")" && touch "$${f}" || true; ` + + ` done && ` + + ` ${config.IncrementalDexInputCmd} --classesJar $in --dexTarget $out --deps $d8Deps --outputDir $outDir --packageOutputDir $outDir/packages && ` + + ` $d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in --packages $out.rsp --mod-packages $out.inc.rsp --package-output $outDir/packages; ` + + `else ` + + ` rm -rf "$outDir" && mkdir -p "$outDir" && ` + + ` $r8Template${config.R8Cmd} ${config.R8Flags} $r8Flags -injars $in --output $outDir ` + + ` --no-data-resources ` + + ` -printmapping ${outDict} ` + + ` -printconfiguration ${outConfig} ` + + ` -printusage ${outUsage} ` + + ` --deps-file ${out}.d && ` + + ` touch "${outDict}" "${outConfig}" "${outUsage}"; ` + + `fi && ` + + `${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` + + `rm -rf ${outUsageDir} && ` + + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` + + `if [ -f "$out.input.pc_state.new" ]; then mv "$out.input.pc_state.new" "$out.input.pc_state" && ` + + `rm -rf $out.input.pc_state.new; fi && ` + + `if [ -f "$out.deps.pc_state.new" ]; then mv "$out.deps.pc_state.new" "$out.deps.pc_state" && ` + + `rm -rf $out.deps.pc_state.new; fi && ` + + `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar" `, + CommandDeps: []string{ + "${config.IncrementalDexInputCmd}", + "${config.D8Cmd}", + "${config.R8Cmd}", + "${config.SoongZipCmd}", + "${config.MergeZipsCmd}", + }, + }, map[string]*remoteexec.REParams{ + "$d8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "d8"}, + Inputs: []string{"${config.D8Jar}"}, + ExecStrategy: "${config.RED8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$r8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "r8"}, + Inputs: []string{"$implicits", "${config.R8Jar}"}, + OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}", "${outR8ArtProfile}"}, + ExecStrategy: "${config.RER8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$outDir/classes.dex.jar"}, + ExecStrategy: "${config.RED8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", + "d8Flags", "d8Deps", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile"}, []string{"implicits"}) + var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + @@ -195,6 +322,7 @@ var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar"`, CommandDeps: []string{ "${config.D8Cmd}", + "${config.D8Jar}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, @@ -250,7 +378,9 @@ var d8r8, d8r8RE = pctx.MultiCommandRemoteStaticRules("d8r8", `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar" `, CommandDeps: []string{ "${config.D8Cmd}", + "${config.D8Jar}", "${config.R8Cmd}", + "${config.R8Jar}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, @@ -301,6 +431,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", Deps: blueprint.DepsGCC, CommandDeps: []string{ "${config.R8Cmd}", + "${config.R8Jar}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, @@ -330,8 +461,14 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", }, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile"}, []string{"implicits"}) +var proguardDictToProto = pctx.AndroidStaticRule("proguard_dict_to_proto", blueprint.RuleParams{ + Command: `${symbols_map} -r8 $in -location $location -write_if_changed $out`, + Restat: true, + CommandDeps: []string{"${symbols_map}"}, +}, "location") + func (d *dexer) dexCommonFlags(ctx android.ModuleContext, - dexParams *compileDexParams) (flags []string, deps android.Paths) { + dexParams *compileDexParams) (flags []string, deps android.Paths, incD8Compatible bool) { flags = d.dexProperties.Dxflags // Translate all the DX flags to D8 ones until all the build files have been migrated @@ -401,36 +538,41 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, } flags = append(flags, "--min-api "+strconv.Itoa(minApiFlagValue)) + incD8Compatible = false + // Incremental d8 does not have libraries passed to it for speed, so any + // desugaring with library classes is not possible. + // To cater for this we only enable incD8 when platform build flag is passed + // as it automatically disables desugaring. if addAndroidPlatformBuildFlag { flags = append(flags, "--android-platform-build") + incD8Compatible = true } - return flags, deps + return flags, deps, incD8Compatible } -func (d *dexer) d8Flags(ctx android.ModuleContext, dexParams *compileDexParams) (d8Flags []string, d8Deps android.Paths, artProfileOutput *android.OutputPath) { +func (d *dexer) d8Flags(ctx android.ModuleContext, dexParams *compileDexParams, useD8Inc bool) (d8Flags []string, d8Deps android.Paths, artProfileOutput *android.OutputPath) { flags := dexParams.flags d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...) d8Flags = append(d8Flags, flags.dexClasspath.FormRepeatedClassPath("--lib ")...) - d8Deps = append(d8Deps, flags.bootClasspath...) d8Deps = append(d8Deps, flags.dexClasspath...) - - if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil { - d8Flags = append(d8Flags, flags...) - d8Deps = append(d8Deps, deps...) - artProfileOutput = profileOutput + if !useD8Inc { + if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil { + d8Flags = append(d8Flags, flags...) + d8Deps = append(d8Deps, deps...) + artProfileOutput = profileOutput + } } return d8Flags, d8Deps, artProfileOutput } -func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, debugMode bool) (r8Flags []string, r8Deps android.Paths, artProfileOutput *android.OutputPath) { - flags := dexParams.flags - opt := d.dexProperties.Optimize +func (d *dexer) r8DepLibFlags(ctx android.ModuleContext, dexParams *compileDexParams) (r8Flags []string, r8Deps android.Paths) { + var depLibs classpath // When an app contains references to APIs that are not in the SDK specified by // its LOCAL_SDK_VERSION for example added by support library or by runtime - // classes added by desugaring, we artifically raise the "SDK version" "linked" by + // classes added by desugaring, we artificially raise the "SDK version" "linked" by // ProGuard, to // - suppress ProGuard warnings of referencing symbols unknown to the lower SDK version. // - prevent ProGuard stripping subclass in the support library that extends class added in the higher SDK version. @@ -443,14 +585,11 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...) } }) - r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) - r8Deps = append(r8Deps, proguardRaiseDeps...) + depLibs = append(depLibs, proguardRaiseDeps...) } - r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars")) - r8Deps = append(r8Deps, flags.bootClasspath...) - r8Flags = append(r8Flags, flags.dexClasspath.FormJavaClassPath("-libraryjars")) - r8Deps = append(r8Deps, flags.dexClasspath...) + depLibs = append(depLibs, dexParams.flags.bootClasspath...) + depLibs = append(depLibs, dexParams.flags.dexClasspath...) transitiveStaticLibsLookupMap := map[android.Path]bool{} for _, jar := range d.transitiveStaticLibsHeaderJarsForR8.ToList() { @@ -465,8 +604,27 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, transitiveHeaderJars = append(transitiveHeaderJars, jar) } transitiveClasspath := classpath(transitiveHeaderJars) - r8Flags = append(r8Flags, transitiveClasspath.FormJavaClassPath("-libraryjars")) - r8Deps = append(r8Deps, transitiveClasspath...) + depLibs = append(depLibs, transitiveClasspath...) + + depLibs = depLibs.FirstUniquePaths() + r8Deps = append(r8Deps, depLibs...) + + var libraryDepArg string + if Bool(d.dexProperties.Optimize.Import_libraries_as_classpath) { + libraryDepArg = "--classpath " + } else { + libraryDepArg = "--lib " + } + r8Flags = append(r8Flags, depLibs.FormRepeatedClassPath(libraryDepArg)...) + + return r8Flags, r8Deps +} + +func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, debugMode, useD8Inc bool) (r8Flags []string, r8Deps android.Paths, artProfileOutput *android.OutputPath) { + r8Flags, r8Deps = d.r8DepLibFlags(ctx, dexParams) + + flags := dexParams.flags + opt := d.dexProperties.Optimize flagFiles := android.Paths{ android.PathForSource(ctx, "build/make/core/proguard.flags"), @@ -525,7 +683,8 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, // Avoid unnecessary stack frame noise by only injecting source map ids for non-debug // optimized or obfuscated targets. - if (Bool(opt.Optimize) || Bool(opt.Obfuscate)) && !debugMode { + optimize := opt.Optimize.GetOrDefault(ctx, false) + if (optimize || Bool(opt.Obfuscate)) && !debugMode { // TODO(b/213833843): Allow configuration of the prefix via a build variable. var sourceFilePrefix = "go/retraceme " var sourceFileTemplate = "\"" + sourceFilePrefix + "%MAP_ID\"" @@ -538,7 +697,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, r8Flags = append(r8Flags, "-dontshrink") } - if !Bool(opt.Optimize) { + if !optimize { r8Flags = append(r8Flags, "-dontoptimize") } @@ -569,10 +728,12 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, } } - if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil { - r8Flags = append(r8Flags, flags...) - r8Deps = append(r8Deps, deps...) - artProfileOutput = profileOutput + if !useD8Inc { + if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil { + r8Flags = append(r8Flags, flags...) + r8Deps = append(r8Deps, deps...) + artProfileOutput = profileOutput + } } if ctx.Config().UseR8StoreStoreFenceConstructorInlining() { @@ -623,21 +784,23 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam cleanPhonyPath := android.PathForModuleOut(ctx, "dex", dexParams.jarName+"-partialcompileclean").OutputPath outDir := android.PathForModuleOut(ctx, "dex") - zipFlags := "--ignore_missing_files" + zipFlags := "--ignore_missing_files --quiet" if proptools.Bool(d.dexProperties.Uncompress_dex) { zipFlags += " -L 0" } - commonFlags, commonDeps := d.dexCommonFlags(ctx, dexParams) + commonFlags, commonDeps, incD8Compatible := d.dexCommonFlags(ctx, dexParams) // Exclude kotlinc generated files when "exclude_kotlinc_generated_files" is set to true. mergeZipsFlags := "" if proptools.BoolDefault(d.dexProperties.Exclude_kotlinc_generated_files, false) { - mergeZipsFlags = "-stripFile META-INF/*.kotlin_module -stripFile **/*.kotlin_builtins" + mergeZipsFlags = "-stripFile META-INF/**/*.kotlin_module -stripFile **/*.kotlin_builtins" } useR8 := d.effectiveOptimizeEnabled(ctx) useD8 := !useR8 || ctx.Config().PartialCompileFlags().Use_d8 + // d8Inc is applicable only when d8 is allowed. + useD8Inc := useD8 && ctx.Config().PartialCompileFlags().Enable_inc_d8 && incD8Compatible rbeR8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") rbeD8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") var rule blueprint.Rule @@ -669,7 +832,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam }...) description = "r8" debugMode := android.InList("--debug", commonFlags) - r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams, debugMode) + r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams, debugMode, useD8Inc) deps = append(deps, r8Deps...) args["r8Flags"] = strings.Join(append(commonFlags, r8Flags...), " ") if r8ArtProfileOutputPath != nil { @@ -694,25 +857,61 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam args["implicits"] = strings.Join(deps.Strings(), ",") } } + cleanupD8R8, cleanupD8IncR8, cleanupD8Inc := false, false, false if useD8 { description = "d8" - d8Flags, d8Deps, d8ArtProfileOutputPath := d.d8Flags(ctx, dexParams) + d8Flags, d8Deps, d8ArtProfileOutputPath := d.d8Flags(ctx, dexParams, useD8Inc) deps = append(deps, d8Deps...) deps = append(deps, commonDeps...) args["d8Flags"] = strings.Join(append(commonFlags, d8Flags...), " ") if d8ArtProfileOutputPath != nil { artProfileOutputPath = d8ArtProfileOutputPath } + // The file containing dependencies of the current module + // Any change in them may warrant changes in the incremental dex compilation + // source set. + if useD8Inc { + d8DepsFile := android.PathForModuleOut(ctx, dexParams.jarName+".dex.deps.rsp") + android.WriteFileRule(ctx, d8DepsFile, strings.Join(deps.Strings(), "\n")) + deps = append(deps, d8DepsFile) + args["d8Deps"] = d8DepsFile.String() + } // If we are generating both d8 and r8, only use RBE when both are enabled. switch { + // r8 is the selected rule, useD8Inc is the override + case useR8 && rule == r8 && useD8Inc: + rule = d8IncR8 + cleanupD8IncR8 = true + description = "d8IncR8" + // r8 is the selected rule, useD8 is the override case useR8 && rule == r8: rule = d8r8 + cleanupD8R8 = true description = "d8r8" + // rbeR8 is the selected rule, useD8Inc is the override + case useR8 && rule == r8RE && useD8Inc: + rule = d8IncR8RE + cleanupD8IncR8 = true + description = "d8IncR8" + // rbeR8 is the selected rule, useD8 is the override case useR8 && rule == r8RE && rbeD8: rule = d8r8RE + cleanupD8R8 = true description = "d8r8" + // rbeD8 is the selected rule, useD8Inc is the override + case rbeD8 && useD8Inc: + rule = d8IncRE + cleanupD8Inc = true + description = "d8Inc" + // rbeD8 is the selected rule case rbeD8: rule = d8RE + // D8 is the selected rule, useD8Inc is the override + case useD8Inc: + rule = d8Inc + cleanupD8Inc = true + description = "d8Inc" + // D8 is the selected rule default: rule = d8 } @@ -732,7 +931,8 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam Implicits: deps, Args: args, }) - if useR8 && useD8 { + // Run cleanup when d8r8 was used + if cleanupD8R8 { // Generate the rule for partial compile clean. args["builtOut"] = javalibJar.String() ctx.Build(pctx, android.BuildParams{ @@ -744,6 +944,32 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam }) ctx.Phony("partialcompileclean", cleanPhonyPath) } + // Run cleanup when d8IncR8 was used + if cleanupD8IncR8 { + // Generate the rule for partial compile clean. + args["builtOut"] = javalibJar.String() + ctx.Build(pctx, android.BuildParams{ + Rule: d8IncR8Clean, + Description: "d8IncR8Clean", + Output: cleanPhonyPath, + Args: args, + PhonyOutput: true, + }) + ctx.Phony("partialcompileclean", cleanPhonyPath) + } + // Run cleanup when d8Inc was used + if cleanupD8Inc { + // Generate the rule for partial compile clean. + args["builtOut"] = javalibJar.String() + ctx.Build(pctx, android.BuildParams{ + Rule: d8IncClean, + Description: "d8IncClean", + Output: cleanPhonyPath, + Args: args, + PhonyOutput: true, + }) + ctx.Phony("partialcompileclean", cleanPhonyPath) + } if proptools.Bool(d.dexProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath @@ -754,6 +980,64 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam return javalibJar, artProfileOutputPath } +type ProguardZips struct { + DictZip android.Path + DictMapping android.Path + UsageZip android.Path +} + +func BuildProguardZips(ctx android.ModuleContext, modules []android.ModuleOrProxy) ProguardZips { + dictZip := android.PathForModuleOut(ctx, "proguard-dict.zip") + dictZipBuilder := android.NewRuleBuilder(pctx, ctx) + dictZipCmd := dictZipBuilder.Command().BuiltTool("soong_zip").Flag("-d").FlagWithOutput("-o ", dictZip) + + dictMapping := android.PathForModuleOut(ctx, "proguard-dict-mapping.textproto") + dictMappingBuilder := android.NewRuleBuilder(pctx, ctx) + dictMappingCmd := dictMappingBuilder.Command().BuiltTool("symbols_map").Flag("-merge").Output(dictMapping) + + protosDir := android.PathForModuleOut(ctx, "proguard_mapping_protos") + + usageZip := android.PathForModuleOut(ctx, "proguard-usage.zip") + usageZipBuilder := android.NewRuleBuilder(pctx, ctx) + usageZipCmd := usageZipBuilder.Command().BuiltTool("merge_zips").Output(usageZip) + + for _, mod := range modules { + if proguardInfo, ok := android.OtherModuleProvider(ctx, mod, ProguardProvider); ok { + // Maintain these out/target/common paths for backwards compatibility. They may be able + // to be changed if tools look up file locations from the protobuf, but I'm not + // exactly sure how that works. + dictionaryFakePath := fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/proguard_dictionary", proguardInfo.Class, proguardInfo.ModuleName) + dictZipCmd.FlagWithArg("-e ", dictionaryFakePath) + dictZipCmd.FlagWithInput("-f ", proguardInfo.ProguardDictionary) + dictZipCmd.Textf("-e out/target/common/obj/%s/%s_intermediates/classes.jar", proguardInfo.Class, proguardInfo.ModuleName) + dictZipCmd.FlagWithInput("-f ", proguardInfo.ClassesJar) + + protoFile := protosDir.Join(ctx, filepath.Dir(dictionaryFakePath), "proguard_dictionary.textproto") + ctx.Build(pctx, android.BuildParams{ + Rule: proguardDictToProto, + Input: proguardInfo.ProguardDictionary, + Output: protoFile, + Args: map[string]string{ + "location": dictionaryFakePath, + }, + }) + dictMappingCmd.Input(protoFile) + + usageZipCmd.Input(proguardInfo.ProguardUsageZip) + } + } + + dictZipBuilder.Build("proguard_dict_zip", "Building proguard dictionary zip") + dictMappingBuilder.Build("proguard_dict_mapping_proto", "Building proguard mapping proto") + usageZipBuilder.Build("proguard_usage_zip", "Building proguard usage zip") + + return ProguardZips{ + DictZip: dictZip, + DictMapping: dictMapping, + UsageZip: usageZip, + } +} + type ProguardInfo struct { ModuleName string Class string diff --git a/java/dexpreopt.go b/java/dexpreopt.go index e8e1cd405..c42997b92 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -644,7 +644,7 @@ func checkSystemServerOrder(ctx android.ModuleContext, libName string) { config := dexpreopt.GetGlobalConfig(ctx) jars := config.AllSystemServerClasspathJars(ctx) jarIndex := config.AllSystemServerJars(ctx).IndexOfJar(libName) - ctx.WalkDeps(func(dep android.Module, parent android.Module) bool { + ctx.WalkDepsProxy(func(dep android.ModuleProxy, parent android.ModuleProxy) bool { tag := ctx.OtherModuleDependencyTag(dep) // Ideally this should only be walking relevant dependencies, but to maintain existing behavior // for now just exclude any known irrelevant dependencies that would lead to incorrect errors. diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 228704355..f302915b4 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -540,7 +540,7 @@ func (dbj *dexpreoptBootJars) DepsMutator(ctx android.BottomUpMutatorContext) { // This dependency will be used to get the path to the deapexed dex boot jars and profile (via a provider) func addDependenciesOntoSelectedBootImageApexes(ctx android.BottomUpMutatorContext, apexes ...string) { psi := android.PrebuiltSelectionInfoMap{} - ctx.VisitDirectDepsWithTag(apexContributionsMetadataDepTag, func(am android.Module) { + ctx.VisitDirectDepsProxyWithTag(apexContributionsMetadataDepTag, func(am android.ModuleProxy) { if info, exists := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); exists { psi = info } @@ -562,9 +562,9 @@ func addDependenciesOntoSelectedBootImageApexes(ctx android.BottomUpMutatorConte } } -func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.Module { +func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.ModuleProxy { return ctx.Config().Once(dexBootJarsFragmentsKey, func() interface{} { - fragments := make(map[string]android.Module) + fragments := make(map[string]android.ModuleProxy) type moduleInApexPair struct { module string @@ -574,7 +574,7 @@ func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android. var modulesInApexes []moduleInApexPair // Find the list of modules in apexes. - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { if !isActiveModule(ctx, child) { return false } @@ -596,7 +596,7 @@ func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android. for _, moduleInApex := range modulesInApexes { // Find a desired module in an apex. - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { t := ctx.OtherModuleDependencyTag(child) if bcpTag, ok := t.(bootclasspathDependencyTag); ok { if bcpTag.typ == platform { @@ -615,10 +615,10 @@ func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android. } return fragments - }).(map[string]android.Module) + }).(map[string]android.ModuleProxy) } -func getBootclasspathFragmentByApex(ctx android.ModuleContext, apexName string) android.Module { +func getBootclasspathFragmentByApex(ctx android.ModuleContext, apexName string) android.ModuleProxy { return gatherBootclasspathFragments(ctx)[apexName] } @@ -767,6 +767,7 @@ func (d *dexpreoptBootJars) buildBootZip(ctx android.ModuleContext) { Inputs: []android.Path{ bootZipMetadataTmp, globalSoong.UffdGcFlag, + globalSoong.AssumeValueFlags, newlineFile, }, Output: bootZipMetadata, @@ -863,7 +864,7 @@ func generateBootImage(ctx android.ModuleContext, imageConfig *bootImageConfig) type apexJarModulePair struct { apex string - jarModule android.Module + jarModule android.ModuleProxy } func getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []apexJarModulePair { @@ -923,9 +924,9 @@ func (m *apexNameToApexExportsInfoMap) javaLibraryDexPathOnHost(ctx android.Modu } // Returns the stem of an artifact inside a prebuilt apex -func ModuleStemForDeapexing(m android.Module) string { - bmn, _ := m.(interface{ BaseModuleName() string }) - return bmn.BaseModuleName() +func ModuleStemForDeapexing(ctx android.OtherModuleProviderContext, m android.ModuleOrProxy) string { + info := android.OtherModuleProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + return info.BaseModuleName } // Returns the java libraries exported by the apex for hiddenapi and dexpreopt @@ -934,11 +935,11 @@ func ModuleStemForDeapexing(m android.Module) string { // 2. Legacy: An edge to java_library or java_import (java_sdk_library) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes // TODO: b/308174306 - Once all mainline modules have been flagged, drop (2) func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNameToApexExportsInfoMap apexNameToApexExportsInfoMap) android.Path { - if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, ModuleStemForDeapexing(pair.jarModule)); found { + if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, ModuleStemForDeapexing(ctx, pair.jarModule)); found { return dex } // TODO: b/308174306 - Remove the legacy mechanism - if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) { + if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(ctx, pair.jarModule) { // This gives us the dex jar with the hidden API flags encoded from the monolithic hidden API // files or the dex jar extracted from a prebuilt APEX. We can't use this for a boot jar for // a source APEX because there is no guarantee that it is the same as the jar packed into the @@ -949,7 +950,7 @@ func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNam } else { // Use exactly the same jar that is packed into the APEX. fragment := getBootclasspathFragmentByApex(ctx, pair.apex) - if fragment == nil { + if fragment.IsNil() { ctx.ModuleErrorf("Boot jar '%[1]s' is from APEX '%[2]s', but a bootclasspath_fragment for "+ "APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars", pair.jarModule.Name(), @@ -1110,20 +1111,25 @@ func getProfilePathForApex(ctx android.ModuleContext, apexName string, apexNameT } // TODO: b/308174306 - Remove the legacy mechanism fragment := getBootclasspathFragmentByApex(ctx, apexName) - if fragment == nil { + if fragment.IsNil() { ctx.ModuleErrorf("Boot image config imports profile from '%[2]s', but a "+ "bootclasspath_fragment for APEX '%[2]s' doesn't exist or is not added as a "+ "dependency of dex_bootjars", apexName) return nil } - return fragment.(commonBootclasspathFragment).getProfilePath() + + if info, ok := android.OtherModuleProvider(ctx, fragment, BootclasspathFragmentInfoProvider); ok { + return info.ProfilePathOnHost + } else { + panic(fmt.Errorf("missing BootclasspathFragmentInfoProvider in %s", fragment)) + } } func getApexNameToApexExportsInfoMap(ctx android.ModuleContext) apexNameToApexExportsInfoMap { apexNameToApexExportsInfoMap := apexNameToApexExportsInfoMap{} - ctx.VisitDirectDeps(func(am android.Module) { + ctx.VisitDirectDepsProxy(func(am android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(am) if bcpTag, ok := tag.(bootclasspathDependencyTag); ok && bcpTag.typ == dexpreoptBootJar { if bcpTag.moduleInApex == "" { @@ -1323,6 +1329,8 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p cmd.Flag(global.BootFlags) } + cmd.Text("$(cat").Input(globalSoong.AssumeValueFlags).Text(")") + if extraFlags != "" { cmd.Flag(extraFlags) } @@ -1381,6 +1389,10 @@ const failureMessage = `ERROR: Dex2oat failed to compile a boot image. It is likely that the boot classpath is inconsistent. Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.` +// bootImageProfileRuleCommon contains the common logic for generating boot image profiles for both +// the platform and the ART module when building from source. +// Building from prebuilts is not handled here. Instead, the profile is extracted from the prebuilt +// ART module. func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles android.Paths, dexLocations []string) android.WritablePath { globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) @@ -1389,33 +1401,35 @@ func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles return nil } - 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) var profiles android.Paths if len(global.BootImageProfiles) > 0 { + // The most common case. The profiles are specified by + // `PRODUCT_DEX_PREOPT_BOOT_IMAGE_PROFILE_LOCATION`. + // - On a bundled build, this list contains both the ART profile and the frameworks profile. + // - On an unbundled build with ART source code being present, this list only contains the ART + // profile. profiles = append(profiles, global.BootImageProfiles...) - } else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() { - profiles = append(profiles, path.Path()) } else { - // No profile (not even a default one, which is the case on some branches - // like master-art-host that don't have frameworks/base). + // No profile specified. This means we are building an unbundled build with ART source code + // being absent, meaning we are not building the platform or the ART module, so we don't need + // a profile. // Return nil and continue without profile. return nil } - if path := android.ExistentPathForSource(ctx, artProfile); path.Valid() { - profiles = append(profiles, path.Path()) - } + extraProfile := "frameworks/base/boot/boot-image-profile-extra.txt" if path := android.ExistentPathForSource(ctx, extraProfile); path.Valid() { profiles = append(profiles, path.Path()) } + + // Remove duplicates while preserving order to ensure deterministic builds. + profiles = android.FirstUniquePaths(profiles) + + // We concatenate the profiles into a single file. Later, `profman` filters the entries based on + // `dexFiles` to only keep the relevant ones. For example, when this function is called for + // generating the profile for the ART module, `profman` only keeps the entries for the ART module + // and not the platform. bootImageProfile := android.PathForModuleOut(ctx, name, "boot-image-profile.txt") rule.Command().Text("cat").Inputs(profiles).Text(">").Output(bootImageProfile) @@ -1621,7 +1635,7 @@ func (dbj *artBootImages) DepsMutator(ctx android.BottomUpMutatorContext) { } func (d *artBootImages) GenerateAndroidBuildActions(ctx android.ModuleContext) { - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(m) if bcpTag, ok := tag.(bootclasspathDependencyTag); ok && bcpTag.typ == dexpreoptBootJar { if bcpTag.moduleInApex != "" { diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go index 9d0f539ba..f7d46144a 100644 --- a/java/dexpreopt_check.go +++ b/java/dexpreopt_check.go @@ -95,16 +95,17 @@ func (m *dexpreoptSystemserverCheck) GenerateAndroidBuildActions(ctx android.Mod global := dexpreopt.GetGlobalConfig(ctx) targets := ctx.Config().Targets[android.Android] - ctx.VisitDirectDepsWithTag(systemServerJarDepTag, func(systemServerJar android.Module) { + ctx.VisitDirectDepsProxyWithTag(systemServerJarDepTag, func(systemServerJar android.ModuleProxy) { partition := "system" - if systemServerJar.InstallInSystemExt() && ctx.Config().InstallApexSystemServerDexpreoptSamePartition() { + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, systemServerJar, android.CommonModuleInfoProvider) + if commonInfo.SystemExtSpecific && ctx.Config().InstallApexSystemServerDexpreoptSamePartition() { partition = ctx.DeviceConfig().SystemExtPath() // system_ext } var dexLocation string - if m, ok := systemServerJar.(ModuleWithStem); ok { - dexLocation = dexpreopt.GetSystemServerDexLocation(ctx, global, m.Stem()) + if javaInfo, ok := android.OtherModuleProvider(ctx, systemServerJar, JavaInfoProvider); ok { + dexLocation = dexpreopt.GetSystemServerDexLocation(ctx, global, javaInfo.Stem) } else { - ctx.PropertyErrorf("dexpreopt_systemserver_check", "%v is not a ModuleWithStem", systemServerJar.Name()) + ctx.PropertyErrorf("dexpreopt_systemserver_check", "%v does not have JavaInfo", systemServerJar.Name()) } odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType, partition) odexPath := getInstallPath(ctx, odexLocation) diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go index f437da02c..775966153 100644 --- a/java/dexpreopt_test.go +++ b/java/dexpreopt_test.go @@ -402,3 +402,44 @@ func TestGenerateProfileEvenIfDexpreoptIsDisabled(t *testing.T) { android.AssertArrayString(t, "outputs", expected, dexpreopt.AllOutputs()) } + +func TestAssumeValueFlags(t *testing.T) { + for _, platformSdkVersion := range []string{"", "28"} { + t.Run(platformSdkVersion, func(t *testing.T) { + preparers := android.GroupFixturePreparers( + PrepareForTestWithDexpreopt, + dexpreopt.PrepareForTestWithDexpreoptConfig, + dexpreopt.FixtureSetEnableUffdGc("false"), + dexpreopt.FixtureSetPlatformSdkVersion(platformSdkVersion), + ) + + result := preparers.RunTestWithBp(t, ` + java_library { + name: "foo", + installable: true, + dex_preopt: { + profile: "art-profile", + }, + srcs: ["a.java"], + sdk_version: "current", + }`) + + ctx := result.TestContext + + // Ensure that we always have a valid (but possibly empty) assumed + // value flags file for use with dex2oat input. + ctx.SingletonForTests(t, "dexpreopt-soong-config").Output("out/soong/dexpreopt/assume_value_flags.txt") + + // If the SDK version is set, it should exist in the command to + // generate the assumed value flags file for use with dex2oat input. + if platformSdkVersion != "" { + rule := ctx.SingletonForTests(t, "dexpreopt-soong-config").Rule("dexpreopt_assume_value_flags") + android.AssertStringDoesContain(t, "", rule.RuleParams.Command, + "echo '--assume-value=Landroid/os/Build$$VERSION;->SDK_INT:"+platformSdkVersion+"'") + android.AssertStringPathsRelativeToTopEquals(t, "", ctx.Config(), []string{ + "out/soong/dexpreopt/assume_value_flags.txt", + }, rule.AllOutputs()) + } + }) + } +} diff --git a/java/droiddoc.go b/java/droiddoc.go index 3faf294de..a65427f8b 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -195,9 +195,6 @@ func apiCheckEnabled(ctx android.ModuleContext, apiToCheck ApiToCheck, apiVersio "them instead.") } return false - } else if ctx.Config().PartialCompileFlags().Disable_stub_validation && - !ctx.Config().BuildFromTextStub() { - return false } else if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" { return true } else if String(apiToCheck.Api_file) != "" { @@ -432,8 +429,8 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { for _, src := range j.properties.Srcs { if moduleName, tag := android.SrcIsModuleWithTag(src); moduleName != "" { otherModule := android.GetModuleProxyFromPathDep(ctx, moduleName, tag) - if otherModule != nil { - if dep, ok := android.OtherModuleProvider(ctx, *otherModule, android.CodegenInfoProvider); ok { + if !otherModule.IsNil() { + if dep, ok := android.OtherModuleProvider(ctx, otherModule, android.CodegenInfoProvider); ok { deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) } } @@ -651,9 +648,9 @@ func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.Rule ctx.PropertyErrorf("custom_template", "must specify a template") } - ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) { - if t, ok := m.(*ExportedDroiddocDir); ok { - cmd.FlagWithArg("-templatedir ", t.dir.String()).Implicits(t.deps) + ctx.VisitDirectDepsProxyWithTag(droiddocTemplateTag, func(m android.ModuleProxy) { + if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok { + cmd.FlagWithArg("-templatedir ", t.Dir.String()).Implicits(t.Deps) } else { ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_exported_dir", ctx.OtherModuleName(m)) } diff --git a/java/droidstubs.go b/java/droidstubs.go index b30c8448a..c2a5c046e 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -18,6 +18,7 @@ import ( "fmt" "path/filepath" "regexp" + "slices" "strings" "github.com/google/blueprint" @@ -36,6 +37,7 @@ type StubsInfo struct { } type DroidStubsInfo struct { + AconfigProtoFiles android.Paths CurrentApiTimestamp android.Path EverythingStubsInfo StubsInfo ExportableStubsInfo StubsInfo @@ -437,6 +439,8 @@ func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) { if d.properties.Api_levels_module != nil { ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module)) } + + d.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } func (d *Droidstubs) sdkValuesFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, metadataDir android.WritablePath) { @@ -593,6 +597,18 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") + // If generating the android API then include android.test.*.jars in the set + // of files passed to Metalava. + filenames := []string{filename} + if filename == "android.jar" { + filenames = append( + filenames, + "android.test.base.jar", + "android.test.mock.jar", + "android.test.runner.jar", + ) + } + // TODO: Avoid the duplication of API surfaces, reuse apiScope. // Add all relevant --android-jar-pattern patterns for Metalava. // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines @@ -648,7 +664,7 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an extensions_dir = t.Dir.String() + "/extensions" } cmd.Implicit(dep) - } else if depBase == filename { + } else if slices.Contains(filenames, depBase) { // Check to see if it matches a dessert release for an SDK, e.g. Android, Car, Wear, etc.. cmd.Implicit(dep) } else if depBase == AndroidPlusUpdatableJar && d.properties.Extensions_info_file != nil { @@ -688,7 +704,16 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an addPattern(AndroidPlusUpdatableJar) } + // Always add the main jar, e.g. android.jar. This will be overridden by + // android-plus-updatable.jar if a pattern for it was added as that comes + // first and neither has a library placeholder. addPattern(filename) + + // If additional file names were added then they are assumed to be + // libraries so match them using a {library} placeholder. + if len(filenames) > 1 { + addPattern("{library}.jar") + } } if extensions_dir != "" { @@ -1251,7 +1276,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Add options for the other optional tasks: API-lint and check-released. // We generate separate timestamp files for them. - doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) && !ctx.Config().PartialCompileFlags().Disable_api_lint + doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) doCheckReleased := apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") writeSdkValues := Bool(d.properties.Write_sdk_values) @@ -1380,15 +1405,12 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { if d.apiLintTimestamp != nil { cmd.Validation(d.apiLintTimestamp) } - if d.checkLastReleasedApiTimestamp != nil { cmd.Validation(d.checkLastReleasedApiTimestamp) } - if d.checkNullabilityWarningsTimestamp != nil { cmd.Validation(d.checkNullabilityWarningsTimestamp) } - rule.Build("metalavaCurrentApiCheck", "check current API") d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "update_current_api.timestamp") @@ -1407,6 +1429,9 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { Input(d.removedApiFile).Flag(removedApiFile.String()) msg = "failed to update public API" + if ctx.Config().GetBuildFlagBool("RELEASE_SRC_DIR_IS_READ_ONLY") { + msg += ". You may need `BUILD_BROKEN_SRC_DIR_IS_WRITABLE=true`" + } rule.Command(). Text("touch").Output(d.updateCurrentApiTimestamp). @@ -1419,6 +1444,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { } droidInfo := DroidStubsInfo{ + AconfigProtoFiles: deps.aconfigProtoFiles, CurrentApiTimestamp: d.CurrentApiTimestamp(), EverythingStubsInfo: StubsInfo{}, ExportableStubsInfo: StubsInfo{}, @@ -1593,6 +1619,10 @@ func (d *PrebuiltStubsSources) StubsSrcJar(_ StubsType) (android.Path, error) { return d.stubsSrcJar, nil } +func (p *PrebuiltStubsSources) DepsMutator(ctx android.BottomUpMutatorContext) { + p.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) +} + func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(p.properties.Srcs) != 1 { ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs)) diff --git a/java/fuzz.go b/java/fuzz.go index 0e239f0ec..922585b8d 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -51,6 +51,12 @@ type JavaFuzzTest struct { jniFilePaths android.Paths } +type JavaFuzzTestInfo struct { + JniFilePaths android.Paths +} + +var JavaFuzzTestInfoProvider = blueprint.NewProvider[JavaFuzzTestInfo]() + // java_fuzz builds and links sources into a `.jar` file for the device. // This generates .class files in a jar which can then be instrumented before // fuzzing in Android Runtime (ART: Android OS on emulator or device) @@ -131,9 +137,41 @@ func (j *JavaFuzzTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } - j.Test.GenerateAndroidBuildActions(ctx) + checkMinSdkVersionMts(ctx, j.MinSdkVersion(ctx)) + j.Test.generateAndroidBuildActionsWithConfig(ctx, nil) + + var compatibilitySupportFiles android.Paths + compatibilitySupportFiles = append(compatibilitySupportFiles, j.implementationJarFile) + compatibilitySupportFiles = append(compatibilitySupportFiles, j.jniFilePaths...) + compatibilitySupportFiles = append(compatibilitySupportFiles, j.fuzzPackagedModule.Corpus...) + if j.fuzzPackagedModule.Dictionary != nil { + compatibilitySupportFiles = append(compatibilitySupportFiles, j.fuzzPackagedModule.Dictionary) + } + + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: j.testProperties.Test_suites, + MainFile: j.outputFile, + MainFileStem: j.Stem(), + MainFileExt: ".jar", + ConfigFile: j.testConfig, + ExtraConfigs: j.extraTestConfigs, + NeedsArchFolder: ctx.Device(), + CompatibilitySupportFiles: compatibilitySupportFiles, + PerTestcaseDirectory: proptools.Bool(j.testProperties.Per_testcase_directory), + }) + + fuzzModuleValidator := fuzz.FuzzModule{ + j.ModuleBase, + j.DefaultableModuleBase, + j.ApexModuleBase, + } - fuzz.SetFuzzPackagedModuleInfo(ctx, &j.fuzzPackagedModule) + if fuzz.IsValid(ctx, fuzzModuleValidator) { + fuzz.SetFuzzPackagedModuleInfo(ctx, &j.fuzzPackagedModule) + android.SetProvider(ctx, JavaFuzzTestInfoProvider, JavaFuzzTestInfo{ + JniFilePaths: j.jniFilePaths, + }) + } } type javaFuzzPackager struct { @@ -149,9 +187,9 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip) s.FuzzTargets = make(map[string]bool) - ctx.VisitAllModules(func(module android.Module) { + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { // Discard non-fuzz targets. - javaFuzzModule, ok := module.(*JavaFuzzTest) + javaInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider) if !ok { return } @@ -159,25 +197,21 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { if !ok { return } + javaFuzzTestInfo, ok := android.OtherModuleProvider(ctx, module, JavaFuzzTestInfoProvider) + if !ok { + return + } + + commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) hostOrTargetString := "target" - if javaFuzzModule.Target().HostCross { + if commonInfo.Target.HostCross { hostOrTargetString = "host_cross" - } else if javaFuzzModule.Host() { + } else if commonInfo.Host { hostOrTargetString = "host" } - fuzzModuleValidator := fuzz.FuzzModule{ - javaFuzzModule.ModuleBase, - javaFuzzModule.DefaultableModuleBase, - javaFuzzModule.ApexModuleBase, - } - - if ok := fuzz.IsValid(ctx, fuzzModuleValidator); !ok { - return - } - - archString := javaFuzzModule.Arch().ArchType.String() + archString := commonInfo.Target.Arch.ArchType.String() archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} @@ -188,14 +222,17 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { files = s.PackageArtifacts(ctx, module, &fuzzInfo, archDir, builder) // Add .jar - if !javaFuzzModule.Host() { - files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.implementationJarFile, DestinationPathPrefix: "classes"}) + if !commonInfo.Host { + for _, jar := range javaInfo.ImplementationJars { + files = append(files, fuzz.FileToZip{SourceFilePath: jar, DestinationPathPrefix: "classes"}) + } } - files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.outputFile}) + outputFile := android.OutputFileForModule(ctx, module, "") + files = append(files, fuzz.FileToZip{SourceFilePath: outputFile}) // Add jni .so files - for _, fPath := range javaFuzzModule.jniFilePaths { + for _, fPath := range javaFuzzTestInfo.JniFilePaths { files = append(files, fuzz.FileToZip{SourceFilePath: fPath}) } @@ -205,6 +242,14 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { } }) s.CreateFuzzPackage(ctx, archDirs, fuzz.Java, pctx) + + // Create the phony and dist rules + ctx.Phony("haiku-java", s.Packages...) + ctx.DistForGoals([]string{"haiku-java"}, s.Packages...) + for _, target := range android.SortedKeys(s.FuzzTargets) { + ctx.Phony("haiku-java", android.PathForPhony(ctx, target)) + } + } func (s *javaFuzzPackager) MakeVars(ctx android.MakeVarsContext) { diff --git a/java/genrule_combiner.go b/java/genrule_combiner.go index 357dc2c76..db6af1ad2 100644 --- a/java/genrule_combiner.go +++ b/java/genrule_combiner.go @@ -95,7 +95,7 @@ func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) // Collect the headers first, so that aconfig flag values for the libraries will override // values from the headers (if they are different). - ctx.VisitDirectDepsWithTag(genruleCombinerHeaderDepTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(genruleCombinerHeaderDepTag, func(m android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { j.headerJars = append(j.headerJars, dep.HeaderJars...) @@ -113,7 +113,7 @@ func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.PropertyErrorf("headers", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) } }) - ctx.VisitDirectDepsWithTag(staticLibTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(staticLibTag, func(m android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { j.implementationJars = append(j.implementationJars, dep.ImplementationJars...) j.implementationAndResourceJars = append(j.implementationAndResourceJars, dep.ImplementationAndResourcesJars...) @@ -178,6 +178,12 @@ func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.SetOutputFiles(javaInfo.HeaderJars, ".hjar") android.SetProvider(ctx, JavaInfoProvider, javaInfo) + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if j.combinedImplementationJar != nil { + moduleInfoJSON.ClassesJar = []string{j.combinedImplementationJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (j *GenruleCombiner) GeneratedSourceFiles() android.Paths { @@ -220,10 +226,6 @@ func (j *GenruleCombiner) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap return nil } -func (j *GenruleCombiner) JacocoReportClassesFile() android.Path { - return nil -} - func (j *GenruleCombiner) AndroidMk() android.AndroidMkData { return android.AndroidMkData{ Class: "JAVA_LIBRARIES", diff --git a/java/hiddenapi.go b/java/hiddenapi.go index c9a1f2bbe..fe2521cca 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -44,8 +44,7 @@ type hiddenAPI struct { // // This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on // this file so using the encoded dex jar here would result in a cycle in the ninja rules. - bootDexJarPath OptionalDexJarPath - bootDexJarPathErr error + bootDexJarPath OptionalDexJarPath // The paths to the classes jars that contain classes and class members annotated with // the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API @@ -57,10 +56,7 @@ type hiddenAPI struct { uncompressDexState *bool } -func (h *hiddenAPI) bootDexJar(ctx android.ModuleErrorfContext) OptionalDexJarPath { - if h.bootDexJarPathErr != nil { - ctx.ModuleErrorf(h.bootDexJarPathErr.Error()) - } +func (h *hiddenAPI) bootDexJar() OptionalDexJarPath { return h.bootDexJarPath } @@ -81,7 +77,7 @@ type hiddenAPIModule interface { } type hiddenAPIIntf interface { - bootDexJar(ctx android.ModuleErrorfContext) OptionalDexJarPath + bootDexJar() OptionalDexJarPath classesJars() android.Paths uncompressDex() *bool } @@ -131,11 +127,6 @@ func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar OptionalDexJ h.active = isModuleInBootClassPath(ctx, module) } -// Store any error encountered during the initialization of hiddenapi structure (e.g. unflagged co-existing prebuilt apexes) -func (h *hiddenAPI) initHiddenAPIError(err error) { - h.bootDexJarPathErr = err -} - func isModuleInBootClassPath(ctx android.BaseModuleContext, module android.Module) bool { // Get the configured platform and apex boot jars. nonApexBootJars := ctx.Config().NonApexBootJars() diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 365005835..d7272433c 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -197,7 +197,7 @@ func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool { return false } -func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType { +func (b hiddenAPIStubsDependencyTag) SdkMemberType(ctx android.ModuleContext, child android.ModuleProxy) android.SdkMemberType { // Do not add additional dependencies to the sdk. if b.fromAdditionalDependency { return nil @@ -205,7 +205,7 @@ func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android // If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs // property, otherwise treat if it was specified in the java_header_libs property. - if javaSdkLibrarySdkMemberType.IsInstance(child) { + if javaSdkLibrarySdkMemberType.IsInstance(ctx, child) { return javaSdkLibrarySdkMemberType } @@ -296,7 +296,7 @@ func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScop // hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if // available, or reports an error. -func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path { +func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.ModuleProxy, kind android.SdkKind) android.Path { var dexJar OptionalDexJarPath if sdkLibrary, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { if ctx.Config().ReleaseHiddenApiExportableStubs() { @@ -304,8 +304,8 @@ func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android. } else { dexJar = sdkLibrary.EverythingStubDexJarPaths[kind] } - } else if j, ok := module.(UsesLibraryDependency); ok { - dexJar = j.DexJarBuildPath(ctx) + } else if j, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok && j.UsesLibraryDependencyInfo != nil { + dexJar = j.DexJarBuildPath } else { ctx.ModuleErrorf("dependency %s of module type %s does not support providing a dex jar", module, ctx.OtherModuleType(module)) return nil @@ -586,7 +586,7 @@ func newHiddenAPIInfo() *HiddenAPIInfo { return &info } -func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) { +func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.ModuleProxy) { // Merge all the information from the fragments. The fragments form a DAG so it is possible that // this will introduce duplicates so they will be resolved after processing all the fragments. for _, fragment := range fragments { @@ -656,7 +656,7 @@ func (s ModuleStubDexJars) stubDexJarForWidestAPIScope() android.Path { type StubDexJarsByModule map[string]ModuleStubDexJars // addStubDexJar adds a stub dex jar path provided by the specified module for the specified scope. -func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.Module, scope *HiddenAPIScope, stubDexJar android.Path) { +func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.ModuleProxy, scope *HiddenAPIScope, stubDexJar android.Path) { name := android.RemoveOptionalPrebuiltPrefix(module.Name()) // Each named module provides one dex jar for each scope. However, in some cases different API @@ -685,13 +685,14 @@ func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module and // conscrypt.module.public.api java_sdk_library which will be the case once the former has been // migrated to a module_lib API. name = "conscrypt.module.public.api" - } else if d, ok := module.(SdkLibraryComponentDependency); ok { - sdkLibraryName := d.SdkLibraryName() - if sdkLibraryName != nil { - // The module is a component of a java_sdk_library so use the name of the java_sdk_library. - // e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then - // use `foo` as the name. - name = *sdkLibraryName + } else { + if slcDepInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryComponentDependencyInfoProvider); ok { + if sdkLibraryName := slcDepInfo.SdkLibraryName; sdkLibraryName != nil { + // The module is a component of a java_sdk_library so use the name of the java_sdk_library. + // e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then + // use `foo` as the name. + name = *sdkLibraryName + } } } stubDexJarsByScope := s[name] @@ -785,7 +786,7 @@ func (i *HiddenAPIPropertyInfo) extractPackageRulesFromProperties(p *HiddenAPIPa i.SplitPackages = p.Hidden_api.Split_packages } -func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.Module) { +func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.ModuleProxy) { for _, module := range contents { if info, ok := android.OtherModuleProvider(ctx, module, hiddenAPIPropertyInfoProvider); ok { i.FlagFilesByCategory.append(info.FlagFilesByCategory) @@ -844,8 +845,8 @@ func newHiddenAPIFlagInput() HiddenAPIFlagInput { // dependencies added in hiddenAPIAddStubLibDependencies. // // That includes paths to the stub dex jars as well as paths to the *removed.txt files. -func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) { - addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) { +func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.ModuleProxy) { + addFromModule := func(ctx android.ModuleContext, module android.ModuleProxy, apiScope *HiddenAPIScope) { sdkKind := apiScope.sdkKind dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind) if dexJar != nil { @@ -868,7 +869,7 @@ func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, conten } } - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(module) if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok { apiScope := hiddenAPIStubsTag.apiScope @@ -927,7 +928,7 @@ type HiddenAPIFlagOutput struct { type bootDexJarByModule map[string]android.Path // addPath adds the path for a module to the map. -func (b bootDexJarByModule) addPath(module android.Module, path android.Path) { +func (b bootDexJarByModule) addPath(module android.ModuleProxy, path android.Path) { b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path } @@ -1168,7 +1169,7 @@ func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name strin // * metadata.csv // * index.csv // * all-flags.csv -func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.Module, input HiddenAPIFlagInput, suffix string) HiddenAPIFlagOutput { +func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.ModuleProxy, input HiddenAPIFlagInput, suffix string) HiddenAPIFlagOutput { hiddenApiSubDir := "modular-hiddenapi" + suffix // Generate the stub-flags.csv. @@ -1176,7 +1177,7 @@ func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootD buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile"+suffix, "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil) // Extract the classes jars from the contents. - classesJars := extractClassesJarsFromModules(contents) + classesJars := extractClassesJarsFromModules(ctx, contents) // Generate the set of flags from the annotations in the source code. annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv") @@ -1266,7 +1267,7 @@ func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, suffix s // 1. New: Direct deps to _selected_ apexes. The apexes contain a ApexExportsInfo // 2. Legacy: An edge to java_sdk_library(_import) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes // TODO: b/308174306 - Once all mainline modules have been flagged, drop (2) -func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule { +func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.ModuleProxy) bootDexJarByModule { bootDexJars := bootDexJarByModule{} apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx) @@ -1283,28 +1284,12 @@ func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android if _, exists := bootDexJars[android.RemoveOptionalPrebuiltPrefix(module.Name())]; exists { continue } - hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module) - if hiddenAPIModule == nil { - continue - } - bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule) + bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, module) bootDexJars.addPath(module, bootDexJar) } return bootDexJars } -func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule { - if hiddenAPIModule, ok := module.(hiddenAPIModule); ok { - return hiddenAPIModule - } else if _, ok := module.(*DexImport); ok { - // Ignore this for the purposes of hidden API processing - } else { - ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module) - } - - return nil -} - // bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule. type bootDexInfo struct { // The path to the dex jar that has not had hidden API flags encoded into it. @@ -1332,15 +1317,16 @@ func (b bootDexInfoByModule) bootDexJars() android.Paths { // extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from // each of the supplied modules which must implement hiddenAPIModule. -func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule { +func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.ModuleProxy) bootDexInfoByModule { bootDexJarsByModule := bootDexInfoByModule{} for _, module := range contents { - hiddenAPIModule := module.(hiddenAPIModule) - bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule) + bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, module) + info := android.OtherModuleProviderOrDefault(ctx, module, JavaInfoProvider) + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) bootDexJarsByModule[module.Name()] = bootDexInfo{ path: bootDexJar, - uncompressDex: *hiddenAPIModule.uncompressDex(), - minSdkVersion: hiddenAPIModule.MinSdkVersion(ctx), + uncompressDex: Bool(info.UncompressDexState), + minSdkVersion: *commonInfo.MinSdkVersion.ApiLevel, } } @@ -1352,37 +1338,31 @@ func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android // If the module does not provide a boot dex jar, i.e. the returned boot dex jar is unset or // invalid, then create a fake path and either report an error immediately or defer reporting of the // error until the path is actually used. -func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path { - bootDexJar := module.bootDexJar(ctx) - if !bootDexJar.Valid() { +func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module android.ModuleProxy) android.Path { + info := android.OtherModuleProviderOrDefault(ctx, module, JavaInfoProvider) + if !info.BootDexJarPath.Valid() { fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name())) - handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason()) + handleMissingDexBootFile(ctx, module, fake, info.BootDexJarPath.InvalidReason()) return fake } - return bootDexJar.Path() + + return info.BootDexJarPath.Path() } // extractClassesJarsFromModules extracts the class jars from the supplied modules. -func extractClassesJarsFromModules(contents []android.Module) android.Paths { +func extractClassesJarsFromModules(ctx android.ModuleContext, contents []android.ModuleProxy) android.Paths { classesJars := android.Paths{} for _, module := range contents { - classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...) + if info, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { + classesJars = append(classesJars, info.HiddenapiClassesJarPaths...) + } } return classesJars } -// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module. -func retrieveClassesJarsFromModule(module android.Module) android.Paths { - if hiddenAPIModule, ok := module.(hiddenAPIModule); ok { - return hiddenAPIModule.classesJars() - } - - return nil -} - // deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by // Soong but should instead only be reported in ninja if the file is actually built. -func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool { +func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.ModuleOrProxy) bool { // Any missing dependency should be allowed. if ctx.Config().AllowMissingDependencies() { return true @@ -1423,7 +1403,7 @@ func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.M // a prebuilt modules that has other variants which are part of an APEX. // // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily. - if android.IsModulePrebuilt(module) { + if android.IsModulePrebuilt(ctx, module) { // An inactive source module can still contribute to the APEX but an inactive prebuilt module // should not contribute to anything. So, rather than have a missing dex jar cause a Soong // failure defer the error reporting to Ninja. Unless the prebuilt build target is explicitly @@ -1445,7 +1425,7 @@ func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.M // handleMissingDexBootFile will either log a warning or create an error rule to create the fake // file depending on the value returned from deferReportingMissingBootDexJar. -func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath, reason string) { +func handleMissingDexBootFile(ctx android.ModuleContext, module android.ModuleOrProxy, fake android.WritablePath, reason string) { if deferReportingMissingBootDexJar(ctx, module) { // Create an error rule that pretends to create the output file but will actually fail if it // is run. @@ -1467,14 +1447,12 @@ func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, // The returned path will usually be to a dex jar file that has been encoded with hidden API flags. // However, under certain conditions, e.g. errors, or special build configurations it will return // a path to a fake file. -func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path { - bootDexJar := module.(interface { - DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath - }).DexJarBuildPath(ctx) - if !bootDexJar.Valid() { +func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.ModuleProxy) android.Path { + info := android.OtherModuleProviderOrDefault(ctx, module, JavaInfoProvider) + if !info.DexJarBuildPath.Valid() { fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name())) - handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason()) + handleMissingDexBootFile(ctx, module, fake, info.DexJarBuildPath.InvalidReason()) return fake } - return bootDexJar.Path() + return info.DexJarBuildPath.Path() } diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go index 1e30c5f82..52e444c6e 100644 --- a/java/hiddenapi_monolithic.go +++ b/java/hiddenapi_monolithic.go @@ -62,8 +62,9 @@ func newMonolithicHiddenAPIInfo(ctx android.ModuleContext, flagFilesByCategory F for _, element := range classpathElements { switch e := element.(type) { case *ClasspathLibraryElement: - classesJars := retrieveClassesJarsFromModule(e.Module()) - monolithicInfo.ClassesJars = append(monolithicInfo.ClassesJars, classesJars...) + if info, ok := android.OtherModuleProvider(ctx, e.Module(), JavaInfoProvider); ok { + monolithicInfo.ClassesJars = append(monolithicInfo.ClassesJars, info.HiddenapiClassesJarPaths...) + } case *ClasspathFragmentElement: fragment := e.Module() @@ -79,7 +80,7 @@ func newMonolithicHiddenAPIInfo(ctx android.ModuleContext, flagFilesByCategory F } // append appends all the files from the supplied info to the corresponding files in this struct. -func (i *MonolithicHiddenAPIInfo) append(ctx android.ModuleContext, otherModule android.Module, other *HiddenAPIInfo) { +func (i *MonolithicHiddenAPIInfo) append(ctx android.ModuleContext, otherModule android.ModuleOrProxy, other *HiddenAPIInfo) { i.FlagsFilesByCategory.append(other.FlagFilesByCategory) i.AnnotationFlagsPaths = append(i.AnnotationFlagsPaths, other.AnnotationFlagsPath) i.MetadataPaths = append(i.MetadataPaths, other.MetadataPath) diff --git a/java/jacoco.go b/java/jacoco.go index 696a0cc37..7a80314c1 100644 --- a/java/jacoco.go +++ b/java/jacoco.go @@ -19,6 +19,7 @@ package java import ( "fmt" "path/filepath" + "slices" "strings" "github.com/google/blueprint" @@ -28,6 +29,10 @@ import ( "android/soong/java/config" ) +func init() { + android.InitRegistrationContext.RegisterParallelSingletonType("device_tests_jacoco_zip", deviceTestsJacocoZipSingletonFactory) +} + var ( jacoco = pctx.AndroidStaticRule("jacoco", blueprint.RuleParams{ Command: `rm -rf $tmpDir && mkdir -p $tmpDir && ` + @@ -167,3 +172,62 @@ func jacocoFilterToSpec(filter string) (string, error) { return spec, nil } + +type JacocoInfo struct { + ReportClassesFile android.Path + Class string + ModuleName string +} + +var ApexJacocoInfoProvider = blueprint.NewProvider[[]JacocoInfo]() + +type BuildJacocoZipContext interface { + android.BuilderContext + android.OtherModuleProviderContext +} + +func BuildJacocoZip(ctx BuildJacocoZipContext, modules []android.ModuleOrProxy, outputFile android.WritablePath) { + jacocoZipBuilder := android.NewRuleBuilder(pctx, ctx) + jacocoZipCmd := jacocoZipBuilder.Command().BuiltTool("soong_zip"). + FlagWithOutput("-o ", outputFile). + Flag("-L 0") + for _, m := range modules { + if javaInfo, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok && javaInfo.JacocoInfo.ReportClassesFile != nil { + jacoco := javaInfo.JacocoInfo + jacocoZipCmd.FlagWithArg("-e ", fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/jacoco-report-classes.jar", jacoco.Class, jacoco.ModuleName)). + FlagWithInput("-f ", jacoco.ReportClassesFile) + } else if info, ok := android.OtherModuleProvider(ctx, m, ApexJacocoInfoProvider); ok { + for _, jacoco := range info { + jacocoZipCmd.FlagWithArg("-e ", fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/jacoco-report-classes.jar", jacoco.Class, jacoco.ModuleName)). + FlagWithInput("-f ", jacoco.ReportClassesFile) + } + } + } + + jacocoZipBuilder.Build("jacoco_report_classes_zip", "Building jacoco report zip") +} + +func deviceTestsJacocoZipSingletonFactory() android.Singleton { + return &deviceTestsJacocoZipSingleton{} +} + +type deviceTestsJacocoZipSingleton struct{} + +// GenerateBuildActions implements android.Singleton. +func (d *deviceTestsJacocoZipSingleton) GenerateBuildActions(ctx android.SingletonContext) { + var deviceTestModules []android.ModuleOrProxy + ctx.VisitAllModuleProxies(func(m android.ModuleProxy) { + if tsm, ok := android.OtherModuleProvider(ctx, m, android.TestSuiteInfoProvider); ok { + if slices.Contains(tsm.TestSuites, "device-tests") { + deviceTestModules = append(deviceTestModules, m) + } + } + }) + + jacocoZip := DeviceTestsJacocoReportZip(ctx) + BuildJacocoZip(ctx, deviceTestModules, jacocoZip) +} + +func DeviceTestsJacocoReportZip(ctx android.PathContext) android.WritablePath { + return android.PathForOutput(ctx, "device_tests_jacoco_report_classes_all.jar") +} diff --git a/java/java.go b/java/java.go index 7032078eb..e6315ec77 100644 --- a/java/java.go +++ b/java/java.go @@ -38,6 +38,8 @@ import ( "android/soong/tradefed" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { registerJavaBuildComponents(android.InitRegistrationContext) @@ -103,8 +105,8 @@ var ( PropertyName: "java_header_libs", SupportsSdk: true, }, - func(_ android.SdkMemberContext, j *Library) android.Path { - headerJars := j.HeaderJars() + func(_ android.SdkMemberContext, j android.ModuleProxy, javaInfo *JavaInfo) android.Path { + headerJars := javaInfo.HeaderJars if len(headerJars) != 1 { panic(fmt.Errorf("there must be only one header jar from %q", j.Name())) } @@ -116,8 +118,8 @@ var ( } // Export implementation classes jar as part of the sdk. - exportImplementationClassesJar = func(_ android.SdkMemberContext, j *Library) android.Path { - implementationJars := j.ImplementationAndResourcesJars() + exportImplementationClassesJar = func(_ android.SdkMemberContext, j android.ModuleProxy, javaInfo *JavaInfo) android.Path { + implementationJars := javaInfo.ImplementationAndResourcesJars if len(implementationJars) != 1 { panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name())) } @@ -160,9 +162,9 @@ var ( PropertyName: "java_boot_libs", SupportsSdk: true, }, - func(ctx android.SdkMemberContext, j *Library) android.Path { + func(ctx android.SdkMemberContext, j android.ModuleProxy, javaInfo *JavaInfo) android.Path { if snapshotRequiresImplementationJar(ctx) { - return exportImplementationClassesJar(ctx, j) + return exportImplementationClassesJar(ctx, j, javaInfo) } // Java boot libs are only provided in the SDK to provide access to their dex implementation @@ -202,7 +204,7 @@ var ( // This was only added in Tiramisu. SupportedBuildReleaseSpecification: "Tiramisu+", }, - func(ctx android.SdkMemberContext, j *Library) android.Path { + func(ctx android.SdkMemberContext, _ android.ModuleProxy, _ *JavaInfo) android.Path { // Java systemserver libs are only provided in the SDK to provide access to their dex // implementation jar for use by dexpreopting. They do not need to provide an actual // implementation jar but the java_import will need a file that exists so just copy an empty @@ -234,6 +236,7 @@ var ( }, "jar_name", "partition", "main_class") ) +// @auto-generate: gob type ProguardSpecInfo struct { // If true, proguard flags files will be exported to reverse dependencies across libs edges // If false, proguard flags files will only be exported to reverse dependencies across @@ -263,11 +266,6 @@ type UsesLibraryDependencyInfo struct { ClassLoaderContexts dexpreopt.ClassLoaderContextMap } -type SdkLibraryComponentDependencyInfo struct { - // The name of the implementation library for the optional SDK library or nil, if there isn't one. - OptionalSdkLibraryImplementation *string -} - type ProvidesUsesLibInfo struct { ProvidesUsesLib *string } @@ -281,6 +279,14 @@ type ModuleWithSdkDepInfo struct { Stubs bool } +type ApexDependencyInfo struct { + // These fields can be different from the ones in JavaInfo, for example, for sdk_library + // the following fields are set since sdk_library inherits the implementations of + // ApexDependency from base, but the same-named fields are not set in JavaInfo. + HeaderJars android.Paths + ImplementationAndResourcesJars android.Paths +} + // JavaInfo contains information about a java module for use by modules that depend on it. type JavaInfo struct { // HeaderJars is a list of jars that can be passed as the javac classpath in order to link @@ -290,6 +296,11 @@ type JavaInfo struct { RepackagedHeaderJars android.Paths + // list of header jars that have not been jarjared. This should only be used as part of + // handling header_jar_override, where we need to use this as the header jars for this implementation of + // The only place this is needed is when `header_jar_override` on another module references this module. + LocalHeaderJarsPreJarjar android.Paths + // set of header jars for all transitive libs deps TransitiveLibsHeaderJarsForR8 depset.DepSet[android.Path] @@ -319,6 +330,9 @@ type JavaInfo struct { // LocalHeaderJars is a list of jars that contain classes from this module, but not from any static dependencies. LocalHeaderJars android.Paths + // KotlinHeaderJars is a jar that only contains Kotlin classes from this module, but not from any static dependencies. + KotlinHeaderJars android.Paths + // AidlIncludeDirs is a list of directories that should be passed to the aidl tool when // depending on this module. AidlIncludeDirs android.Paths @@ -345,9 +359,9 @@ type JavaInfo struct { // requiring disbling turbine for any modules that depend on it. ExportedPluginDisableTurbine bool - // JacocoReportClassesFile is the path to a jar containing uninstrumented classes that will be + // JacocoInfo contains the path to a jar containing uninstrumented classes that will be // instrumented by jacoco. - JacocoReportClassesFile android.Path + JacocoInfo JacocoInfo // StubsLinkType provides information about whether the provided jars are stub jars or // implementation jars. If the provider is set by java_sdk_library, the link type is "unknown" @@ -369,8 +383,6 @@ type JavaInfo struct { UsesLibraryDependencyInfo *UsesLibraryDependencyInfo - SdkLibraryComponentDependencyInfo *SdkLibraryComponentDependencyInfo - ProvidesUsesLibInfo *ProvidesUsesLibInfo MissingOptionalUsesLibs []string @@ -392,6 +404,11 @@ type JavaInfo struct { // this file so using the encoded dex jar here would result in a cycle in the ninja rules. BootDexJarPath OptionalDexJarPath + // The paths to the classes jars that contain classes and class members annotated with + // the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API + // processing. + HiddenapiClassesJarPaths android.Paths + // The compressed state of the dex file being encoded. This is used to ensure that the encoded // dex file has the same state. UncompressDexState *bool @@ -433,8 +450,15 @@ type JavaInfo struct { DexpreopterInfo *DexpreopterInfo - XrefJavaFiles android.Paths - XrefKotlinFiles android.Paths + XrefJavaFiles android.Paths + XrefKotlinFiles android.Paths + OverrideMinSdkVersion *string + CompileDex *bool + SystemModules string + Installable bool + ApexDependencyInfo *ApexDependencyInfo + + MaxSdkVersion android.ApiLevel } var JavaInfoProvider = blueprint.NewProvider[*JavaInfo]() @@ -453,7 +477,8 @@ type DexpreopterInfo struct { } type JavaLibraryInfo struct { - Prebuilt bool + Prebuilt bool + PermittedPackages []string } var JavaLibraryInfoProvider = blueprint.NewProvider[JavaLibraryInfo]() @@ -558,37 +583,59 @@ func IsJniDepTag(depTag blueprint.DependencyTag) bool { return depTag == jniLibTag || depTag == jniInstallTag } +func IsOptionalUsesLibraryDepTag(depTag blueprint.DependencyTag) bool { + if tag, ok := depTag.(usesLibraryDependencyTag); ok { + return tag.optional + } + return depTag == r8LibraryJarTag +} + +// A tag that is used for staging the dependencies of a module, for populating uses libraries +// dependencies. +type usesLibStagingTagStruct struct { + blueprint.BaseDependencyTag +} + +// Mark this tag so dependencies that use it are excluded from APEX contents. +func (t usesLibStagingTagStruct) ExcludeFromApexContents() {} + +var _ android.ExcludeFromApexContentsTag = (*usesLibStagingTagStruct)(nil) + var ( - dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} - dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} - staticLibTag = dependencyTag{name: "staticlib", static: true} - libTag = dependencyTag{name: "javalib", runtimeLinked: true} - sdkLibTag = dependencyTag{name: "sdklib", runtimeLinked: true} - java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true} - pluginTag = dependencyTag{name: "plugin", toolchain: true} - errorpronePluginTag = dependencyTag{name: "errorprone-plugin", toolchain: true} - exportedPluginTag = dependencyTag{name: "exported-plugin", toolchain: true} - bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true} - systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true} - frameworkResTag = dependencyTag{name: "framework-res"} - lineageResTag = dependencyTag{name: "org.lineageos.platform-res"} - kotlinPluginTag = dependencyTag{name: "kotlin-plugin", toolchain: true} - proguardRaiseTag = dependencyTag{name: "proguard-raise"} - certificateTag = dependencyTag{name: "certificate"} - instrumentationForTag = dependencyTag{name: "instrumentation_for"} - extraLintCheckTag = dependencyTag{name: "extra-lint-check", toolchain: true} - jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true} - r8LibraryJarTag = dependencyTag{name: "r8-libraryjar", runtimeLinked: true} - traceReferencesTag = dependencyTag{name: "trace-references"} - syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"} - javaApiContributionTag = dependencyTag{name: "java-api-contribution"} - aconfigDeclarationTag = dependencyTag{name: "aconfig-declaration"} - jniInstallTag = dependencyTag{name: "jni install", runtimeLinked: true, installable: true} - usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false) - usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true) - usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true) - usesLibCompat29ReqTag = makeUsesLibraryDependencyTag(29, false) - usesLibCompat30OptTag = makeUsesLibraryDependencyTag(30, true) + dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} + dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} + staticLibTag = dependencyTag{name: "staticlib", static: true} + libTag = dependencyTag{name: "javalib", runtimeLinked: true} + sdkLibTag = dependencyTag{name: "sdklib", runtimeLinked: true} + java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true} + pluginTag = dependencyTag{name: "plugin", toolchain: true} + errorpronePluginTag = dependencyTag{name: "errorprone-plugin", toolchain: true} + exportedPluginTag = dependencyTag{name: "exported-plugin", toolchain: true} + bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true} + systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true} + frameworkResTag = dependencyTag{name: "framework-res"} + lineageResTag = dependencyTag{name: "org.lineageos.platform-res"} + kotlinPluginTag = dependencyTag{name: "kotlin-plugin", toolchain: true} + composeEmbeddablePluginTag = dependencyTag{name: "compose-embeddable-plugin", toolchain: true} + composePluginTag = dependencyTag{name: "compose-plugin", toolchain: true} + proguardRaiseTag = dependencyTag{name: "proguard-raise"} + certificateTag = dependencyTag{name: "certificate"} + headerJarOverrideTag = dependencyTag{name: "header-jar-override"} + instrumentationForTag = dependencyTag{name: "instrumentation_for"} + extraLintCheckTag = dependencyTag{name: "extra-lint-check", toolchain: true} + jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true} + r8LibraryJarTag = dependencyTag{name: "r8-libraryjar", runtimeLinked: true} + traceReferencesTag = dependencyTag{name: "trace-references"} + syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"} + javaApiContributionTag = dependencyTag{name: "java-api-contribution"} + aconfigDeclarationTag = dependencyTag{name: "aconfig-declaration"} + jniInstallTag = dependencyTag{name: "jni install", runtimeLinked: true, installable: true} + usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false) + usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true) + usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true) + usesLibCompat29ReqTag = makeUsesLibraryDependencyTag(29, false) + usesLibCompat30OptTag = makeUsesLibraryDependencyTag(30, true) + usesLibStagingTag = usesLibStagingTagStruct{} ) // A list of tags for deps used for compiling a module. @@ -607,6 +654,8 @@ var ( bootClasspathTag, systemModulesTag, java9LibTag, + composePluginTag, + composeEmbeddablePluginTag, kotlinPluginTag, syspropPublicStubDepTag, instrumentationForTag, @@ -721,9 +770,14 @@ type deps struct { srcJars android.Paths systemModules *systemModules aidlPreprocess android.OptionalPath + composeEmbeddablePlugin android.OptionalPath + composePlugin android.OptionalPath kotlinPlugins android.Paths aconfigProtoFiles android.Paths + headerJarOverride android.OptionalPath + headerJarOverridePreJarjar android.OptionalPath + disableTurbine bool transitiveStaticLibsHeaderJars []depset.DepSet[android.Path] @@ -1152,7 +1206,8 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { }) android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{ - Prebuilt: false, + Prebuilt: false, + PermittedPackages: j.properties.Permitted_packages, }) if javaInfo != nil { @@ -1160,8 +1215,6 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { javaInfo.ExtraOutputFiles = j.extraOutputFiles javaInfo.DexJarFile = j.dexJarFile javaInfo.InstallFile = j.installFile - javaInfo.BootDexJarPath = j.bootDexJarPath - javaInfo.UncompressDexState = j.uncompressDexState javaInfo.Active = j.active javaInfo.BuiltInstalled = j.builtInstalled javaInfo.ConfigPath = j.configPath @@ -1186,7 +1239,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { if j.dexer.proguardDictionary.Valid() { android.SetProvider(ctx, ProguardProvider, ProguardInfo{ - ModuleName: ctx.ModuleName(), + ModuleName: android.ModuleNameWithPossibleOverride(ctx), Class: "JAVA_LIBRARIES", ProguardDictionary: j.dexer.proguardDictionary.Path(), ProguardUsageZip: j.dexer.proguardUsageZip.Path(), @@ -1232,7 +1285,7 @@ func buildComplianceMetadata(ctx android.ModuleContext) { // Static deps staticDepNames := make([]string, 0) staticDepFiles := android.Paths{} - ctx.VisitDirectDepsWithTag(staticLibTag, func(module android.Module) { + ctx.VisitDirectDepsProxyWithTag(staticLibTag, func(module android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { staticDepNames = append(staticDepNames, module.Name()) staticDepFiles = append(staticDepFiles, dep.ImplementationJars...) @@ -1286,6 +1339,9 @@ func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { j.usesLibrary.deps(ctx, false) j.deps(ctx) + if j.properties.Header_jar_override != "" { + ctx.AddVariationDependencies(nil, headerJarOverrideTag, j.properties.Header_jar_override) + } if j.SdkLibraryName() != nil && strings.HasSuffix(j.Name(), ".impl") { if dexpreopt.IsDex2oatNeeded(ctx) { dexpreopt.RegisterToolDeps(ctx) @@ -1340,7 +1396,7 @@ type librarySdkMemberType struct { // Function to retrieve the appropriate output jar (implementation or header) from // the library. - jarToExportGetter func(ctx android.SdkMemberContext, j *Library) android.Path + jarToExportGetter func(ctx android.SdkMemberContext, j android.ModuleProxy, javaInfo *JavaInfo) android.Path // Function to compute the snapshot relative path to which the named library's // jar should be copied. @@ -1360,9 +1416,9 @@ func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (mt *librarySdkMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*Library) - return ok +func (mt *librarySdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + info, ok := android.OtherModuleProvider(ctx, module, JavaLibraryInfoProvider) + return ok && !info.Prebuilt } func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { @@ -1389,26 +1445,30 @@ type librarySdkMemberProperties struct { DexPreoptProfileGuided *bool `supported_build_releases:"UpsideDownCake+"` } -func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - j := variant.(*Library) +func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + //j := variant.(*Library) + mctx := ctx.SdkModuleContext() + commonInfo := android.OtherModulePointerProviderOrDefault(mctx, variant, android.CommonModuleInfoProvider) + javaInfo := android.OtherModulePointerProviderOrDefault(mctx, variant, JavaInfoProvider) + libraryInfo := android.OtherModuleProviderOrDefault(mctx, variant, JavaLibraryInfoProvider) - p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(ctx, j) + p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(ctx, variant, javaInfo) - p.AidlIncludeDirs = j.AidlIncludeDirs() + p.AidlIncludeDirs = javaInfo.AidlIncludeDirs - p.PermittedPackages = j.PermittedPackagesForUpdatableBootJars() + p.PermittedPackages = libraryInfo.PermittedPackages // If the min_sdk_version was set then add the canonical representation of the API level to the // snapshot. - if j.overridableProperties.Min_sdk_version != nil { - canonical, err := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String()) + if javaInfo.OverrideMinSdkVersion != nil { + canonical, err := android.ReplaceFinalizedCodenames(mctx.Config(), commonInfo.MinSdkVersion.ApiLevel.String()) if err != nil { ctx.ModuleErrorf("%s", err) } p.MinSdkVersion = proptools.StringPtr(canonical) } - if j.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided { + if javaInfo.ProfileGuided { p.DexPreoptProfileGuided = proptools.BoolPtr(true) } } @@ -1660,6 +1720,12 @@ type JavaTestImport struct { dexJarFile android.Path } +type JavaTestInfo struct { + TestConfig android.Path +} + +var JavaTestInfoProvider = blueprint.NewProvider[JavaTestInfo]() + func (j *Test) InstallInTestcases() bool { // Host java tests install into $(HOST_OUT_JAVA_LIBRARIES), and then are copied into // testcases by base_rules.mk. @@ -1815,6 +1881,7 @@ func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.Test.generateAndroidBuildActionsWithConfig(ctx, configs) + j.Test.javaTestSetTestsuiteInfo(ctx) android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ TestcaseRelDataFiles: testcaseRel(j.data), OutputFile: j.outputFile, @@ -1837,6 +1904,7 @@ func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { checkMinSdkVersionMts(ctx, j.MinSdkVersion(ctx)) j.generateAndroidBuildActionsWithConfig(ctx, nil) + j.javaTestSetTestsuiteInfo(ctx) } func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) { @@ -1942,29 +2010,29 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, } } moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, j.testProperties.Test_mainline_modules...) +} +func (j *Test) javaTestSetTestsuiteInfo(ctx android.ModuleContext) { // Install test deps - if !ctx.Config().KatiEnabled() { - pathInTestCases := android.PathForModuleInstall(ctx, "testcases", ctx.ModuleName()) - if j.testConfig != nil { - ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".config", j.testConfig) - } - dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml") - if dynamicConfig.Valid() { - ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path()) - } - testDeps := append(j.data, j.extraTestConfigs...) - for _, data := range android.SortedUniquePaths(testDeps) { - dataPath := android.DataPath{SrcPath: data} - ctx.InstallTestData(pathInTestCases, []android.DataPath{dataPath}) - } - if j.outputFile != nil { - ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".jar", j.outputFile) - } + var testData []android.DataPath + for _, data := range j.data { + dataPath := android.DataPath{SrcPath: data} + testData = append(testData, dataPath) } + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: j.testProperties.Test_suites, + MainFile: j.outputFile, + MainFileStem: j.Stem(), + MainFileExt: ".jar", + ConfigFile: j.testConfig, + ExtraConfigs: j.extraTestConfigs, + NeedsArchFolder: ctx.Device(), + NonArchData: testData, + PerTestcaseDirectory: proptools.Bool(j.testProperties.Per_testcase_directory), + }) - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: j.testProperties.Test_suites, + android.SetProvider(ctx, JavaTestInfoProvider, JavaTestInfo{ + TestConfig: j.testConfig, }) } @@ -1979,12 +2047,20 @@ func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContex moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") } optionalConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml") + var config android.Path if optionalConfig.Valid() { + config = optionalConfig.Path() moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String()) } - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: j.testHelperLibraryProperties.Test_suites, + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: j.testHelperLibraryProperties.Test_suites, + MainFile: j.outputFile, + MainFileStem: j.Stem(), + MainFileExt: ".jar", + ConfigFile: config, + NeedsArchFolder: ctx.Device(), + PerTestcaseDirectory: proptools.Bool(j.testHelperLibraryProperties.Per_testcase_directory), }) } @@ -2008,8 +2084,8 @@ func (mt *testSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, d ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (mt *testSdkMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*Test) +func (mt *testSdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + _, ok := android.OtherModuleProvider(ctx, module, JavaTestInfoProvider) return ok } @@ -2028,16 +2104,14 @@ type testSdkMemberProperties struct { TestConfig android.Path } -func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - test := variant.(*Test) - - implementationJars := test.ImplementationJars() +func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + implementationJars := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, JavaInfoProvider).ImplementationJars if len(implementationJars) != 1 { - panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name())) + panic(fmt.Errorf("there must be only one implementation jar from %q", variant.Name())) } p.JarToExport = implementationJars[0] - p.TestConfig = test.testConfig + p.TestConfig = android.OtherModuleProviderOrDefault(ctx.SdkModuleContext(), variant, JavaTestInfoProvider).TestConfig } func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { @@ -2358,6 +2432,10 @@ func (ap *JavaApiContribution) GenerateAndroidBuildActions(ctx android.ModuleCon }) } +func (ap *JavaApiContribution) DepsMutator(ctx android.BottomUpMutatorContext) { + ap.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) +} + type ApiLibrary struct { android.ModuleBase android.DefaultableModuleBase @@ -2546,7 +2624,6 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { apiContributions := al.properties.Api_contributions addValidations := !ctx.Config().IsEnvTrue("DISABLE_STUB_VALIDATION") && !ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") && - !ctx.Config().PartialCompileFlags().Disable_stub_validation && proptools.BoolDefault(al.properties.Enable_validation, true) for _, apiContributionName := range apiContributions { ctx.AddDependency(ctx.Module(), javaApiContributionTag, apiContributionName) @@ -2584,6 +2661,8 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations { ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName) } + + al.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } // Map where key is the api scope name and value is the int value @@ -2722,7 +2801,15 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { cmd.FlagForEachInput("--migrate-nullness ", previousApiFiles) } - al.addValidation(ctx, cmd, al.validationPaths) + // While we could use SOONG_USE_PARTIAL_COMPILE in the validation's rule, that would unduly + // complicate the code for minimal benefit. Instead, add a phony + // target to let the developer manually run the validation if they so + // desire. + ctx.Phony("stub-validation", al.validationPaths...) + ctx.Phony(ctx.ModuleName()+"-stub-validation", al.validationPaths...) + if !ctx.Config().PartialCompileFlags().Disable_stub_validation { + al.addValidation(ctx, cmd, al.validationPaths) + } generateRevertAnnotationArgs(ctx, cmd, al.stubsType, al.aconfigProtoFiles) @@ -2789,6 +2876,13 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { } setExtraJavaInfo(ctx, al, javaInfo) android.SetProvider(ctx, JavaInfoProvider, javaInfo) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if al.stubsJar != nil { + moduleInfoJSON.ClassesJar = []string{al.stubsJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (al *ApiLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { @@ -3006,10 +3100,6 @@ func (j *Import) CreatedByJavaSdkLibraryName() *string { return j.properties.Created_by_java_sdk_library_name } -func (a *Import) JacocoReportClassesFile() android.Path { - return nil -} - 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)...) @@ -3017,6 +3107,8 @@ func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { if ctx.Device() && Bool(j.dexProperties.Compile_dex) { sdkDeps(ctx, android.SdkContext(j), j.dexer) } + + j.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } func (j *Import) commonBuildActions(ctx android.ModuleContext) { @@ -3268,13 +3360,21 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { android.SetProvider(ctx, JavaInfoProvider, javaInfo) android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{ - Prebuilt: true, + Prebuilt: true, + PermittedPackages: j.properties.Permitted_packages, }) ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, "") ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, ".jar") buildComplianceMetadata(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if j.combinedImplementationFile != nil { + moduleInfoJSON.ClassesJar = []string{j.combinedImplementationFile.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (j *Import) maybeInstall(ctx android.ModuleContext, jarName string, outputFile android.Path) { @@ -3476,10 +3576,6 @@ func (j *DexImport) Stem() string { return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name()) } -func (a *DexImport) JacocoReportClassesFile() android.Path { - return nil -} - func (j *DexImport) IsInstallable() bool { return true } @@ -3498,7 +3594,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")) j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &j.dexpreopter) - inputJar := ctx.ExpandSource(j.properties.Jars[0], "jars") + inputJar := android.PathForModuleSrc(ctx, j.properties.Jars[0]) dexOutputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".jar") if j.dexpreopter.uncompressedDex { @@ -3544,6 +3640,8 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { javaInfo := &JavaInfo{} setExtraJavaInfo(ctx, j, javaInfo) + javaInfo.BootDexJarPath = j.dexJarFile + android.SetProvider(ctx, JavaInfoProvider, javaInfo) android.SetProvider(ctx, JavaDexImportInfoProvider, JavaDexImportInfo{}) @@ -3695,7 +3793,7 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.ModuleProxy, 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 := dep.SdkLibraryComponentDependencyInfo; lib != nil && lib.OptionalSdkLibraryImplementation != nil { + } else if lib, ok := android.OtherModuleProvider(ctx, depModule, SdkLibraryComponentDependencyInfoProvider); ok && lib.OptionalSdkLibraryImplementation != nil { if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation)+".impl" { sdkLib = lib.OptionalSdkLibraryImplementation } @@ -3823,12 +3921,6 @@ func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo } } - if slcDep, ok := module.(SdkLibraryComponentDependency); ok { - javaInfo.SdkLibraryComponentDependencyInfo = &SdkLibraryComponentDependencyInfo{ - OptionalSdkLibraryImplementation: slcDep.OptionalSdkLibraryImplementation(), - } - } - if pul, ok := module.(ProvidesUsesLib); ok { javaInfo.ProvidesUsesLibInfo = &ProvidesUsesLibInfo{ ProvidesUsesLib: pul.ProvidesUsesLib(), @@ -3857,6 +3949,18 @@ func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo javaInfo.DexJarBuildPath = mm.DexJarBuildPath(ctx) } + if ham, ok := module.(hiddenAPIModule); ok { + javaInfo.BootDexJarPath = ham.bootDexJar() + javaInfo.HiddenapiClassesJarPaths = ham.classesJars() + javaInfo.UncompressDexState = ham.uncompressDex() + } + + if mm, ok := module.(interface { + MaxSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel + }); ok { + javaInfo.MaxSdkVersion = mm.MaxSdkVersion(ctx) + } + if di, ok := module.(DexpreopterInterface); ok { javaInfo.DexpreopterInfo = &DexpreopterInfo{ OutputProfilePathOnHost: di.OutputProfilePathOnHost(), @@ -3869,4 +3973,16 @@ func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo javaInfo.XrefJavaFiles = xr.XrefJavaFiles() javaInfo.XrefKotlinFiles = xr.XrefKotlinFiles() } + + if sdk, ok := module.(android.SdkContext); ok { + javaInfo.SystemModules = sdk.SystemModules() + javaInfo.SdkVersion = sdk.SdkVersion(ctx) + } + + if ap, ok := module.(ApexDependency); ok { + javaInfo.ApexDependencyInfo = &ApexDependencyInfo{ + HeaderJars: ap.HeaderJars(), + ImplementationAndResourcesJars: ap.ImplementationAndResourcesJars(), + } + } } diff --git a/java/java_gob_enc.go b/java/java_gob_enc.go new file mode 100644 index 000000000..69d21c8ab --- /dev/null +++ b/java/java_gob_enc.go @@ -0,0 +1,54 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package java + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + ProguardSpecInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ProguardSpecInfo) }) +} + +func (r ProguardSpecInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.Export_proguard_flags_files); err != nil { + return err + } + + if err = r.ProguardFlagsFiles.EncodeInterface(buf); err != nil { + return err + } + + if err = r.UnconditionallyExportedProguardFlags.EncodeInterface(buf); err != nil { + return err + } + return err +} + +func (r *ProguardSpecInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.Export_proguard_flags_files) + if err != nil { + return err + } + + if err = r.ProguardFlagsFiles.DecodeInterface(buf); err != nil { + return err + } + + if err = r.UnconditionallyExportedProguardFlags.DecodeInterface(buf); err != nil { + return err + } + + return err +} + +var ProguardSpecInfoGobRegId int16 + +func (r ProguardSpecInfo) GetTypeId() int16 { + return ProguardSpecInfoGobRegId +} diff --git a/java/java_test.go b/java/java_test.go index 1ba78d49b..6e80dcd34 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2740,16 +2740,6 @@ func TestMultiplePrebuilts(t *testing.T) { contents: ["%v"], } ` - hasDep := func(ctx *android.TestResult, m android.Module, wantDep android.Module) bool { - t.Helper() - var found bool - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } hasFileWithStem := func(m android.TestingModule, stem string) bool { t.Helper() @@ -2793,7 +2783,8 @@ func TestMultiplePrebuilts(t *testing.T) { // check that rdep gets the correct variation of dep foo := ctx.ModuleForTests(t, "foo", "android_common") expectedDependency := ctx.ModuleForTests(t, tc.expectedDependencyName, "android_common") - android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", foo.Module().Name(), tc.expectedDependencyName), true, hasDep(ctx, foo.Module(), expectedDependency.Module())) + android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", foo.Module().Name(), tc.expectedDependencyName), + true, android.HasDirectDep(ctx, foo.Module(), expectedDependency.Module())) // check that output file of dep is always bar.jar // The filename should be agnostic to source/prebuilt/prebuilt_version @@ -2920,6 +2911,59 @@ func TestApiLibraryAconfigDeclarations(t *testing.T) { android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "flags-config-exportable.xml") } +func TestDroidstubsAconfigPropagation(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeMockFs(map[string][]byte{ + "a/A.java": nil, + "a/current.txt": nil, + "a/removed.txt": nil, + }), + ).RunTestWithBp(t, ` + aconfig_declarations { + name: "bar", + package: "com.example.package", + container: "com.android.foo", + srcs: [ + "bar.aconfig", + ], + } + droidstubs { + name: "foo", + srcs: ["a/A.java"], + api_surface: "public", + check_api: { + current: { + api_file: "a/current.txt", + removed_api_file: "a/removed.txt", + } + }, + aconfig_declarations: [ + "bar", + ], + } + + java_library { + name: "baz", + srcs: [ + ":foo", + ], + } + `) + + bazModule := result.ModuleForTests(t, "baz", "android_common").Module() + javaInfo, _ := android.OtherModuleProvider(result, bazModule, JavaInfoProvider) + aconfigProtos := javaInfo.AconfigIntermediateCacheOutputPaths + + android.AssertIntEquals(t, "Expected to provide one aconfig proto file", 1, len(aconfigProtos)) + android.AssertStringDoesContain( + t, + "Expected to provide bar/aconfig-cache.pb", + strings.Join(aconfigProtos.Strings(), " "), + "bar/aconfig-cache.pb", + ) +} + func TestTestOnly(t *testing.T) { t.Parallel() ctx := android.GroupFixturePreparers( @@ -3150,7 +3194,7 @@ func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTe } } - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m android.Module) { addActuals(m, android.TestOnlyProviderKey) }) @@ -3171,7 +3215,7 @@ func TestNativeRequiredDepOfJavaBinary(t *testing.T) { t.Parallel() findDepsOfModule := func(ctx *android.TestContext, module android.Module, depName string) []blueprint.Module { var ret []blueprint.Module - ctx.VisitDirectDeps(module, func(dep blueprint.Module) { + ctx.VisitDirectDeps(module, func(dep android.Module) { if dep.Name() == depName { ret = append(ret, dep) } diff --git a/java/jdeps.go b/java/jdeps.go index 56142c89b..c624e13bd 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -100,7 +100,7 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont Rule: android.Touch, Output: jfpath, }) - ctx.DistForGoals([]string{"general-tests", "dist_files"}, j.outputPath) + ctx.DistForGoals([]string{"general-tests", "dist_files", "module-info"}, j.outputPath) } func createJsonFile(moduleInfos map[string]android.IdeInfo, jfpath android.WritablePath) error { diff --git a/java/kotlin.go b/java/kotlin.go index 308bb0305..68890bdda 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -26,25 +26,99 @@ import ( "github.com/google/blueprint" ) -var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports{Goma: true}, +type KotlinCompileData struct { + pcStateFileNew android.OutputPath + pcStateFilePrior android.OutputPath + diffFile android.OutputPath +} + +const inputDeltaCmd = `${config.FindInputDeltaCmd} --target "$out" ` + + `--inputs_file "$out.rsp" --new_state "$newStateFile" --prior_state "$priorStateFile" > $sourceDeltaFile` + +const nonIncKotlinCmd = `rm -rf "$classesDir" "$headerClassesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + + `mkdir -p "$classesDir" "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` + + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` + + `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + + ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` + + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + + `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` + + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + + ` $kotlincFlags -jvm-target $kotlinJvmTarget $composePluginFlag $kotlincPluginFlags -Xbuild-file=$kotlinBuildFile ` + + ` -kotlin-home $emptyDir ` + + ` -Xplugin=${config.KotlinAbiGenPluginJar} ` + + ` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` + + `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` + + `${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` + + `rm -rf "$srcJarDir" "$classesDir" "$headerClassesDir" ` + +const moveDeltaStateFile = `mv $newStateFile $priorStateFile && rm $sourceDeltaFile` + +var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports{}, blueprint.RuleParams{ - Command: `rm -rf "$classesDir" "$headerClassesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + - `mkdir -p "$classesDir" "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` + + Command: inputDeltaCmd + ` && ` + nonIncKotlinCmd + ` && ` + moveDeltaStateFile, + CommandDeps: []string{ + "${config.FindInputDeltaCmd}", + "${config.KotlincCmd}", + "${config.KotlinCompilerJar}", + "${config.KotlinPreloaderJar}", + "${config.KotlinReflectJar}", + "${config.KotlinScriptRuntimeJar}", + "${config.KotlinStdlibJar}", + "${config.KotlinTrove4jJar}", + "${config.KotlinAnnotationJar}", + "${config.KotlinAbiGenPluginJar}", + "${config.GenKotlinBuildFileCmd}", + "${config.SoongZipCmd}", + "${config.ZipSyncCmd}", + }, + Rspfile: "$out.rsp", + RspfileContent: `$in`, + Restat: true, + }, + "kotlincFlags", "composePluginFlag", "kotlincPluginFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", + "classesDir", "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", + "newStateFile", "priorStateFile", "sourceDeltaFile", "name") + +// TODO: does incremental work with RBE? +var kotlinIncremental = pctx.AndroidRemoteStaticRule("kotlin-incremental", android.RemoteRuleSupports{}, + blueprint.RuleParams{ + Command: // Incremental + + inputDeltaCmd + ` && ` + + + `if [ "$$SOONG_USE_PARTIAL_COMPILE" = "true" ]; then ` + + `rm -rf "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + + `mkdir -p "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` + `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + - `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` + + `${config.KotlinIncrementalClientBinary} ${config.KotlincGlobalFlags} ` + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + - ` $kotlincFlags -jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile ` + - ` -kotlin-home $emptyDir ` + + ` $kotlincFlags $composeEmbeddablePluginFlag $kotlincPluginFlags ` + + ` -jvm-target $kotlinJvmTarget -build-file=$kotlinBuildFile ` + + ` -source-delta-file=$sourceDeltaFile` + + ` -kotlin-home=$emptyDir ` + + ` -root-dir=$incrementalRootDir` + + ` -output-dir=$outputDir` + + ` -build-dir=$buildDir ` + + ` -working-dir=$workDir ` + ` -Xplugin=${config.KotlinAbiGenPluginJar} ` + ` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` + `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` + `${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` + - `rm -rf "$srcJarDir" "$classesDir" "$headerClassesDir"`, + `rm -rf "$srcJarDir" ; ` + + + // Else non incremental + `else ` + + nonIncKotlinCmd + ` ; ` + + `fi && ` + + moveDeltaStateFile, + CommandDeps: []string{ + "${config.FindInputDeltaCmd}", "${config.KotlincCmd}", + "${config.KotlinIncrementalClientBinary}", "${config.KotlinCompilerJar}", "${config.KotlinPreloaderJar}", "${config.KotlinReflectJar}", @@ -61,8 +135,9 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports RspfileContent: `$in`, Restat: true, }, - "kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir", - "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name") + "kotlincFlags", "composeEmbeddablePluginFlag", "composePluginFlag", "kotlincPluginFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "incrementalRootDir", + "classesDir", "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", + "name", "outputDir", "buildDir", "workDir", "newStateFile", "priorStateFile", "sourceDeltaFile") var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe", blueprint.RuleParams{ @@ -74,7 +149,7 @@ var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe", // Skip header jars, those should not have an effect on kythe results. ` --args '${config.KotlincGlobalFlags} ` + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + - ` $kotlincFlags -jvm-target $kotlinJvmTarget ` + + ` $kotlincFlags $kotlincPluginFlags -jvm-target $kotlinJvmTarget ` + `${config.KotlincKytheGlobalFlags}'`, CommandDeps: []string{ "${config.KotlinKytheExtractor}", @@ -83,7 +158,14 @@ var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe", Rspfile: "$out.rsp", RspfileContent: "$in", }, - "classpath", "kotlincFlags", "commonSrcFilesList", "kotlinJvmTarget", "outJar", "srcJars", "srcJarDir", + "classpath", "kotlincFlags", "kotlincPluginFlags", "commonSrcFilesList", "kotlinJvmTarget", "outJar", "srcJars", "srcJarDir", +) + +var kotlinIncrementalClean = pctx.AndroidStaticRule("kotlin-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "$cpSnapshot" "$outDir" "$buildDir" "$workDir"`, + }, + "cpSnapshot", "outDir", "buildDir", "workDir", ) func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath { @@ -104,10 +186,10 @@ 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 (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath, - srcFiles, commonSrcFiles, srcJars android.Paths, - flags javaBuilderFlags) { + srcFiles, commonSrcFiles, srcJars android.Paths, flags javaBuilderFlags, compileData KotlinCompileData, incremental bool) { var deps android.Paths + var orderOnlyDeps android.Paths deps = append(deps, flags.kotlincClasspath...) deps = append(deps, flags.kotlincDeps...) deps = append(deps, srcJars...) @@ -123,43 +205,97 @@ func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutp commonSrcFilesArg = "--common_srcs " + commonSrcsList.String() } + associateJars := getAssociateJars(ctx, j.properties.Associates) + if len(associateJars) > 0 { + flags.kotlincFlags += " -Xfriend-paths=" + strings.Join(associateJars.Strings(), ",") + deps = append(deps, associateJars...) + + // Prepend the associates classes jar in the classpath, so that they take priority over the other jars. + var newClasspath classpath + newClasspath = append(newClasspath, associateJars...) + newClasspath = append(newClasspath, flags.kotlincClasspath...) + flags.kotlincClasspath = newClasspath + } + classpathRspFile := android.PathForModuleOut(ctx, "kotlinc", "classpath.rsp") android.WriteFileRule(ctx, classpathRspFile, strings.Join(flags.kotlincClasspath.Strings(), " ")) deps = append(deps, classpathRspFile) + rule := kotlinc + description := "kotlinc" + incrementalRootDir := android.PathForModuleOut(ctx, "kotlinc") + outputDir := "classes" + buildDir := "build" + workDir := "work" + args := map[string]string{ + "classpath": classpathRspFile.String(), + "kotlincFlags": flags.kotlincFlags, + "kotlincPluginFlags": flags.kotlincPluginFlags, + "commonSrcFilesArg": commonSrcFilesArg, + "srcJars": strings.Join(srcJars.Strings(), " "), + "classesDir": android.PathForModuleOut(ctx, "kotlinc", outputDir).String(), + "headerClassesDir": android.PathForModuleOut(ctx, "kotlinc", "header_classes").String(), + "headerJar": headerOutputFile.String(), + "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(), + "kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(), + "emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(), + "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(), + "name": kotlinName, + "newStateFile": compileData.pcStateFileNew.String(), + "priorStateFile": compileData.pcStateFilePrior.String(), + "sourceDeltaFile": compileData.diffFile.String(), + "composePluginFlag": flags.composePluginFlag, + } + if incremental { + rule = kotlinIncremental + description = "kotlin-incremental" + args["outputDir"] = outputDir + args["buildDir"] = buildDir + args["workDir"] = workDir + args["incrementalRootDir"] = incrementalRootDir.String() + args["sourceDeltaFile"] = compileData.diffFile.String() + args["composeEmbeddablePluginFlag"] = flags.composeEmbeddablePluginFlag + } + ctx.Build(pctx, android.BuildParams{ - Rule: kotlinc, - Description: "kotlinc", - Output: outputFile, - ImplicitOutput: headerOutputFile, - Inputs: srcFiles, - Implicits: deps, + Rule: rule, + Description: description, + Inputs: srcFiles, + Implicits: deps, + OrderOnly: orderOnlyDeps, + Output: outputFile, + ImplicitOutputs: []android.WritablePath{headerOutputFile, compileData.pcStateFilePrior}, + Args: args, + }) + + cleanPhonyPath := android.PathForModuleOut(ctx, "partialcompileclean", kotlinName) + ctx.Build(pctx, android.BuildParams{ + Rule: kotlinIncrementalClean, + Description: "kotlin-partialcompileclean", + Output: cleanPhonyPath, + Inputs: android.Paths{}, Args: map[string]string{ - "classpath": classpathRspFile.String(), - "kotlincFlags": flags.kotlincFlags, - "commonSrcFilesArg": commonSrcFilesArg, - "srcJars": strings.Join(srcJars.Strings(), " "), - "classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(), - "headerClassesDir": android.PathForModuleOut(ctx, "kotlinc", "header_classes").String(), - "headerJar": headerOutputFile.String(), - "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(), - "kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(), - "emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(), - "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(), - "name": kotlinName, + // TODO: add this cp snapshot as a param to the incremental compiler. + "cpSnapshot": incrementalRootDir.Join(ctx, "shrunk-classpath-snapshot.bin").String(), + "outDir": incrementalRootDir.Join(ctx, outputDir).String(), + "buildDir": incrementalRootDir.Join(ctx, buildDir).String(), + "workDir": incrementalRootDir.Join(ctx, workDir).String(), }, + PhonyOutput: true, }) + ctx.Phony("partialcompileclean", cleanPhonyPath) // 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(), + "classpath": classpathRspFile.String(), + "kotlincFlags": flags.kotlincFlags, + "kotlincPluginFlags": flags.kotlincPluginFlags, + "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() @@ -176,7 +312,49 @@ func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutp } } -var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{Goma: true}, +func getAssociateJars(ctx android.ModuleContext, associates []string) android.Paths { + if len(associates) == 0 { + return nil + } + + associatesFound := make(map[string]bool) + for _, name := range associates { + associatesFound[name] = false + } + + var associateJars android.Paths + ctx.VisitDirectDepsProxy(func(depModule android.ModuleProxy) { + depName := ctx.OtherModuleName(depModule) + _, isAssociate := associatesFound[depName] + if !isAssociate { + return + } + + associatesFound[depName] = true + depInfo, ok := android.OtherModuleProvider(ctx, depModule, JavaInfoProvider) + if !ok { + ctx.PropertyErrorf("Associates", "associate module '%s' is not a Java module", depName) + return + } + + if len(depInfo.KotlinHeaderJars) == 0 { + ctx.PropertyErrorf("Associates", "associate module '%s' is not a Kotlin module", depName) + return + } + + associateJars = append(associateJars, depInfo.KotlinHeaderJars...) + }) + + for name, found := range associatesFound { + if !found { + ctx.PropertyErrorf("Associates", "associate module '%s' must also be listed as a direct dependency (e.g. in static_libs or libs)", name) + } + } + + return associateJars +} + +var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{}, blueprint.RuleParams{ Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` + `mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` + @@ -187,7 +365,8 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` + `${config.KaptSuppressJDK9Warnings} ${config.KotlincSuppressJDK9Warnings} ` + - `${config.JavacHeapFlags} $kotlincFlags -Xplugin=${config.KotlinKaptJar} ` + + `${config.JavacHeapFlags} $kotlincFlags ` + + `-Xplugin=${config.KotlinKaptJar} ` + `-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` + `-P plugin:org.jetbrains.kotlin.kapt3:classes=$kaptDir/classes ` + `-P plugin:org.jetbrains.kotlin.kapt3:stubs=$kaptDir/stubs ` + @@ -198,7 +377,6 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp `$kaptProcessor ` + `-Xbuild-file=$kotlinBuildFile && ` + `${config.SoongZipCmd} -jar -write_if_changed -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` + - `if [ -f "$out.pc_state.new" ]; then mv "$out.pc_state.new" "$out.pc_state"; fi && ` + `rm -rf "$srcJarDir"`, CommandDeps: []string{ "${config.FindInputDeltaCmd}", @@ -214,7 +392,7 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp Restat: true, }, "kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor", - "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "kaptDir", "kotlinJvmTarget", + "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "kaptDir", "kotlinBuildFile", "name", "classesJarOut") // kotlinKapt performs Kotlin-compatible annotation processing. It takes .kt and .java sources and srcjars, and runs diff --git a/java/kotlin_test.go b/java/kotlin_test.go index 4b56cff1c..b2556b7af 100644 --- a/java/kotlin_test.go +++ b/java/kotlin_test.go @@ -199,6 +199,34 @@ func TestKotlin(t *testing.T) { } } +func TestSortKotlincFlags(t *testing.T) { + t.Parallel() + + t.Run("Successful sorting of kotlincFlags", func(t *testing.T) { + t.Parallel() + bp := ` + java_library { + name: "Foo", + srcs: ["Foo.kt"], + kotlincflags: ["-Ja", "-Xb", "-JCz", "-JCy", "-JCx", "-Xd"] + } + ` + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, bp) + + module := result.ModuleForTests(t, "Foo", "android_common") + kotlincRule := module.Rule("kotlinc") + expectedFlags := "-Ja -JCz -JCy -JCx -Xb -Xd" + + kotlincFlags := kotlincRule.Args["kotlincFlags"] + if !strings.Contains(kotlincFlags, expectedFlags) { + t.Errorf("kotlincFlags expected to have -J flags sorted first:\n Flags: %s\n Expected: %s", kotlincFlags, expectedFlags) + } + }) + +} + func TestKapt(t *testing.T) { t.Parallel() bp := ` @@ -462,7 +490,7 @@ func TestKotlinCompose(t *testing.T) { withCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String()) android.AssertStringDoesContain(t, "missing compose compiler plugin", - withCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String()) + withCompose.VariablesForTestsRelativeToTop()["composePluginFlag"], "-Xplugin="+composeCompiler.String()) android.AssertStringListContains(t, "missing kapt compose compiler dependency", withCompose.Rule("kapt").Implicits.Strings(), composeCompiler.String()) @@ -471,7 +499,7 @@ func TestKotlinCompose(t *testing.T) { noCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String()) android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin", - noCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String()) + noCompose.VariablesForTestsRelativeToTop()["composePluginFlag"], "-Xplugin="+composeCompiler.String()) } func TestKotlinPlugin(t *testing.T) { @@ -510,7 +538,7 @@ func TestKotlinPlugin(t *testing.T) { withKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String()) android.AssertStringDoesContain(t, "missing kotlin plugin", - withKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String()) + withKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincPluginFlags"], "-Xplugin="+kotlinPlugin.String()) android.AssertStringListContains(t, "missing kapt kotlin plugin dependency", withKotlinPlugin.Rule("kapt").Implicits.Strings(), kotlinPlugin.String()) @@ -521,3 +549,95 @@ func TestKotlinPlugin(t *testing.T) { android.AssertStringDoesNotContain(t, "unexpected kotlin plugin", noKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String()) } + +func TestKotlinAssociates(t *testing.T) { + t.Parallel() + + targets := []string{"FooUtils", "FooTest"} + for _, target := range targets { + t.Run("Successful associate linking of "+target, func(t *testing.T) { + t.Parallel() + bp := ` + java_library { + name: "Foo", + srcs: ["Foo.kt"], + } + + java_library { + name: "FooUtils", + srcs: ["FooUtils.kt"], + libs: ["Foo"], + associates: ["Foo"], + } + + java_test { + name: "FooTest", + srcs: ["FooTest.kt"], + static_libs: ["Foo"], + associates: ["Foo"], + } + ` + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, bp) + + module := result.ModuleForTests(t, target, "android_common") + kotlincRule := module.Rule("kotlinc") + expectedFriendPath := "out/soong/.intermediates/Foo/android_common/kotlin_headers/Foo.jar" + expectedFlag := "-Xfriend-paths=" + expectedFriendPath + + kotlincFlags := kotlincRule.Args["kotlincFlags"] + if !strings.Contains(kotlincFlags, expectedFlag) { + t.Errorf("kotlincFlags missing expected friend path:\n Flags: %s\n Expected: %s", kotlincFlags, expectedFlag) + } + + classpathRspFile := module.Output("kotlinc/classpath.rsp") + classpathContent := android.ContentFromFileRuleForTests(t, result.TestContext, classpathRspFile) + classpathEntries := strings.Fields(classpathContent) + android.AssertStringPathRelativeToTopEquals(t, "first classpath entry", result.Config, expectedFriendPath, classpathEntries[0]) + }) + } + + t.Run("Error: Associate not a dependency", func(t *testing.T) { + t.Parallel() + bp := ` + java_library { + name: "Foo", + srcs: ["Foo.kt"], + } + + java_library { + name: "FooUtils", + srcs: ["FooUtils.kt"], + associates: ["Foo"], + } + ` + android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\QAssociates: associate module 'Foo' must also be listed as a direct dependency\E`, + )).RunTestWithBp(t, bp) + }) + + t.Run("Error: Associate not a Kotlin module", func(t *testing.T) { + t.Parallel() + bp := ` + java_library { + name: "Foo", + srcs: ["Foo.java"], + } + + java_library { + name: "FooUtils", + srcs: ["FooUtils.kt"], + libs: ["Foo"], + associates: ["Foo"], + } + ` + android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\QAssociates: associate module 'Foo' is not a Kotlin module\E`, + )).RunTestWithBp(t, bp) + }) +} diff --git a/java/lint.go b/java/lint.go index dc1e51ffb..7f6c67a5a 100644 --- a/java/lint.go +++ b/java/lint.go @@ -28,6 +28,8 @@ import ( "android/soong/remoteexec" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // lint checks automatically enforced for modules that have different min_sdk_version than // sdk_version var updatabilityChecks = []string{"NewApi"} @@ -196,6 +198,7 @@ var allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{ var LintProvider = blueprint.NewProvider[*LintInfo]() +// @auto-generate: gob type LintInfo struct { HTML android.Path Text android.Path @@ -580,9 +583,31 @@ func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets, v xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") lintZip(ctx, xmlList, xmlZip, validations) + android.SetProvider(ctx, ModuleLintReportZipsProvider, ModuleLintReportZipsInfo{ + HtmlZip: htmlZip, + TextZip: textZip, + XmlZip: xmlZip, + }) + return android.Paths{htmlZip, textZip, xmlZip} } +type ModuleLintReportZipsInfo struct { + HtmlZip android.Path + TextZip android.Path + XmlZip android.Path +} + +func (i *ModuleLintReportZipsInfo) AllReports() android.Paths { + return android.Paths{ + i.HtmlZip, + i.TextZip, + i.XmlZip, + } +} + +var ModuleLintReportZipsProvider = blueprint.NewProvider[ModuleLintReportZipsInfo]() + type lintSingleton struct { htmlZip android.WritablePath textZip android.WritablePath @@ -652,19 +677,20 @@ func copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.W } func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { + // Dists of lint reports in unbundled builds is handled by unbundled_builder in unbundled.go if ctx.Config().UnbundledBuild() { return } var outputs []*LintInfo - var dirs []string ctx.VisitAllModuleProxies(func(m android.ModuleProxy) { commonInfo := android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + platformAvailabilitInfo := android.OtherModuleProviderOrDefault(ctx, m, android.PlatformAvailabilityInfoProvider) if ctx.Config().KatiEnabled() && !commonInfo.ExportedToMake { return } - if commonInfo.IsApexModule && commonInfo.NotAvailableForPlatform { + if commonInfo.IsApexModule && platformAvailabilitInfo.NotAvailableToPlatform { apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider) if apexInfo.IsForPlatform() { // There are stray platform variants of modules in apexes that are not available for @@ -678,8 +704,6 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { } }) - dirs = android.SortedUniqueStrings(dirs) - zip := func(outputPath android.WritablePath, get func(*LintInfo) android.Path) { var paths android.Paths @@ -705,10 +729,7 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { zip(l.referenceBaselineZip, func(l *LintInfo) android.Path { return l.ReferenceBaseline }) ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip) - - if !ctx.Config().UnbundledBuild() { - ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip) - } + ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip) } func init() { diff --git a/java/lint_gob_enc.go b/java/lint_gob_enc.go new file mode 100644 index 000000000..9779a7639 --- /dev/null +++ b/java/lint_gob_enc.go @@ -0,0 +1,110 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package java + +import ( + "android/soong/android" + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + LintInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LintInfo) }) +} + +func (r LintInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.HTML); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.Text); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.XML); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.ReferenceBaseline); err != nil { + return err + } + + if err = r.TransitiveHTML.EncodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveText.EncodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveXML.EncodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveBaseline.EncodeInterface(buf); err != nil { + return err + } + return err +} + +func (r *LintInfo) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.HTML = nil + } else { + r.HTML = val2.(android.Path) + } + + if val4, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val4 == nil { + r.Text = nil + } else { + r.Text = val4.(android.Path) + } + + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.XML = nil + } else { + r.XML = val6.(android.Path) + } + + if val8, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val8 == nil { + r.ReferenceBaseline = nil + } else { + r.ReferenceBaseline = val8.(android.Path) + } + + if err = r.TransitiveHTML.DecodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveText.DecodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveXML.DecodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveBaseline.DecodeInterface(buf); err != nil { + return err + } + + return err +} + +var LintInfoGobRegId int16 + +func (r LintInfo) GetTypeId() int16 { + return LintInfoGobRegId +} diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 155afc6c2..130f625e9 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -51,16 +51,16 @@ type platformBootclasspathModule struct { properties platformBootclasspathProperties // The apex:module pairs obtained from the configured modules. - configuredModules []android.Module + configuredModules []android.ModuleProxy // The apex:module pairs obtained from the fragments. - fragments []android.Module + fragments []android.ModuleProxy // The map of apex to the fragments they contain. - apexNameToFragment map[string]android.Module + apexNameToFragment map[string]android.ModuleProxy // The map of library modules in the bootclasspath to the fragments that contain them. - libraryToApex map[android.Module]string + libraryToApex map[android.ModuleProxy]string // Path to the monolithic hiddenapi-flags.csv file. hiddenAPIFlagsCSV android.OutputPath @@ -181,8 +181,8 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo // 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(platformBootclasspathImplLibDepTag, func(m android.Module) { + var implLibModule []android.ModuleProxy + ctx.VisitDirectDepsProxyWithTag(platformBootclasspathImplLibDepTag, func(m android.ModuleProxy) { implLibModule = append(implLibModule, m) }) @@ -251,7 +251,7 @@ func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) andr // checkPlatformModules ensures that the non-updatable modules supplied are not part of an // apex module. -func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) { +func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.ModuleProxy) { // TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here. for _, m := range modules { apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider) @@ -266,7 +266,7 @@ func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleCon } // checkApexModules ensures that the apex modules supplied are not from the platform. -func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) { +func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.ModuleProxy) { for _, m := range modules { apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider) fromUpdatableApex := apexInfo.Updatable @@ -298,8 +298,10 @@ func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext } // generateHiddenAPIBuildActions generates all the hidden API related build rules. -func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, - fragments []android.Module, libraryToApex map[android.Module]string, apexNameToFragment map[string]android.Module) bootDexJarByModule { +func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.ModuleProxy, + fragments []android.ModuleProxy, libraryToApex map[android.ModuleProxy]string, + apexNameToFragment map[string]android.ModuleProxy) bootDexJarByModule { + createEmptyHiddenApiFiles := func() { paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} for _, path := range paths { diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index d2ec8bd4f..4d43ba9a6 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -44,8 +44,12 @@ func registerPlatformCompatConfigBuildComponents(ctx android.RegistrationContext } type PlatformCompatConfigInfo struct { - CompatConfig android.OutputPath - SubDir string + CompatConfig android.OutputPath + SubDir string + CompatConfigMetadata android.Path + // Whether to include it in the "merged" XML (merged_compat_config.xml) or not. + IncludeInMergedXml bool + Prebuilt bool } var PlatformCompatConfigInfoProvider = blueprint.NewProvider[PlatformCompatConfigInfo]() @@ -99,14 +103,6 @@ type platformCompatConfigMetadataProvider interface { includeInMergedXml() bool } -type PlatformCompatConfigMetadataInfo struct { - CompatConfigMetadata android.Path - // Whether to include it in the "merged" XML (merged_compat_config.xml) or not. - IncludeInMergedXml bool -} - -var PlatformCompatConfigMetadataInfoProvider = blueprint.NewProvider[PlatformCompatConfigMetadataInfo]() - type PlatformCompatConfigIntf interface { android.Module @@ -141,13 +137,11 @@ func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleCon ctx.SetOutputFiles(android.Paths{p.configFile}, "") android.SetProvider(ctx, PlatformCompatConfigInfoProvider, PlatformCompatConfigInfo{ - CompatConfig: p.CompatConfig(), - SubDir: p.SubDir(), - }) - - android.SetProvider(ctx, PlatformCompatConfigMetadataInfoProvider, PlatformCompatConfigMetadataInfo{ + CompatConfig: p.CompatConfig(), + SubDir: p.SubDir(), CompatConfigMetadata: p.compatConfigMetadata(), IncludeInMergedXml: p.includeInMergedXml(), + Prebuilt: false, }) } @@ -173,9 +167,9 @@ func (b *compatConfigMemberType) AddDependencies(ctx android.SdkDependencyContex ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (b *compatConfigMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*platformCompatConfig) - return ok +func (b *compatConfigMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + info, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigInfoProvider) + return ok && !info.Prebuilt } func (b *compatConfigMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { @@ -192,9 +186,8 @@ type compatConfigSdkMemberProperties struct { Metadata android.Path } -func (b *compatConfigSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - module := variant.(*platformCompatConfig) - b.Metadata = module.metadataFile +func (b *compatConfigSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + b.Metadata = android.OtherModuleProviderOrDefault(ctx.SdkModuleContext(), variant, PlatformCompatConfigInfoProvider).CompatConfigMetadata } func (b *compatConfigSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { @@ -252,9 +245,10 @@ var _ platformCompatConfigMetadataProvider = (*prebuiltCompatConfigModule)(nil) func (module *prebuiltCompatConfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { module.metadataFile = module.prebuilt.SingleSourcePath(ctx) - android.SetProvider(ctx, PlatformCompatConfigMetadataInfoProvider, PlatformCompatConfigMetadataInfo{ + android.SetProvider(ctx, PlatformCompatConfigInfoProvider, PlatformCompatConfigInfo{ CompatConfigMetadata: module.compatConfigMetadata(), IncludeInMergedXml: module.includeInMergedXml(), + Prebuilt: true, }) } @@ -280,7 +274,7 @@ func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.Singlet if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled { return } - if c, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigMetadataInfoProvider); ok { + if c, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigInfoProvider); ok { if !android.IsModulePreferredProxy(ctx, module) { return } diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go index 17fdae962..7d927fc0e 100644 --- a/java/prebuilt_apis_test.go +++ b/java/prebuilt_apis_test.go @@ -20,8 +20,6 @@ import ( "testing" "android/soong/android" - - "github.com/google/blueprint" ) func intPtr(v int) *int { @@ -40,7 +38,7 @@ func TestPrebuiltApis_SystemModulesCreation(t *testing.T) { ).RunTest(t) sdkSystemModules := []string{} - result.VisitAllModules(func(module blueprint.Module) { + result.VisitAllModules(func(module android.Module) { name := android.RemoveOptionalPrebuiltPrefix(module.Name()) if strings.HasPrefix(name, "sdk_") && strings.HasSuffix(name, "_system_modules") { sdkSystemModules = append(sdkSystemModules, name) diff --git a/java/ravenwood.go b/java/ravenwood.go index a942dc653..b096a2592 100644 --- a/java/ravenwood.go +++ b/java/ravenwood.go @@ -16,6 +16,7 @@ package java import ( "strconv" + "android/soong/aconfig" "android/soong/android" "android/soong/tradefed" @@ -37,14 +38,16 @@ var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"} var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"} var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"} var ravenwoodTestInstResourceApkTag = dependencyTag{name: "ravenwoodtest-inst-res-apk"} +var allAconfigModuleTag = dependencyTag{name: "all_aconfig"} var genManifestProperties = pctx.AndroidStaticRule("genManifestProperties", blueprint.RuleParams{ Command: "echo targetSdkVersionInt=$targetSdkVersionInt > $out && " + "echo targetSdkVersionRaw=$targetSdkVersionRaw >> $out && " + "echo packageName=$packageName >> $out && " + - "echo instPackageName=$instPackageName >> $out", - }, "targetSdkVersionInt", "targetSdkVersionRaw", "packageName", "instPackageName") + "echo instPackageName=$instPackageName >> $out && " + + "echo instrumentationClass=$instrumentationClass >> $out", + }, "targetSdkVersionInt", "targetSdkVersionRaw", "packageName", "instPackageName", "instrumentationClass") const ravenwoodUtilsName = "ravenwood-utils" const ravenwoodRuntimeName = "ravenwood-runtime" @@ -87,8 +90,12 @@ type ravenwoodTestProperties struct { // Specify the package name of this test module. // This will be set to the test Context's package name. - //(i.e. Instrumentation.getContext().getPackageName()) + // (i.e. Instrumentation.getContext().getPackageName()) Inst_package_name *string + + // Specify the name of the Instrumentation subclass to use. + // (e.g. "androidx.test.runner.AndroidJUnitRunner") + Instrumentation_class *string } type ravenwoodTest struct { @@ -97,7 +104,9 @@ type ravenwoodTest struct { ravenwoodTestProperties ravenwoodTestProperties testProperties testProperties - testConfig android.Path + + testConfig android.Path + data android.Paths forceOSType android.OsType forceArchType android.ArchType @@ -168,13 +177,31 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { r.forceArchType = ctx.Config().BuildArch r.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{ - TestConfigProp: r.testProperties.Test_config, - TestConfigTemplateProp: r.testProperties.Test_config_template, - TestSuites: r.testProperties.Test_suites, - AutoGenConfig: r.testProperties.Auto_gen_config, - DeviceTemplate: "${RavenwoodTestConfigTemplate}", - HostTemplate: "${RavenwoodTestConfigTemplate}", + TestConfigProp: r.testProperties.Test_config, + TestConfigTemplateProp: r.testProperties.Test_config_template, + OptionsForAutogenerated: r.testProperties.Test_options.Tradefed_options, + TestRunnerOptions: r.testProperties.Test_options.Test_runner_options, + TestSuites: r.testProperties.Test_suites, + AutoGenConfig: r.testProperties.Auto_gen_config, + DeviceTemplate: "${RavenwoodTestConfigTemplate}", + HostTemplate: "${RavenwoodTestConfigTemplate}", }) + r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data) + r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_common_data)...) + r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_data)...) + r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_prefer32_data)...) + r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Host_common_data)...) + + r.data = android.SortedUniquePaths(r.data) + + var testData []android.DataPath + for _, data := range r.data { + dataPath := android.DataPath{SrcPath: data} + testData = append(testData, dataPath) + } + for _, d := range r.extraOutputFiles { + testData = append(testData, android.DataPath{SrcPath: d}) + } // Always enable Ravenizer for ravenwood tests. r.Library.ravenizer.enabled = true @@ -244,20 +271,28 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { targetSdkVersionInt := r.TargetSdkVersion(ctx).FinalOrFutureInt() // FinalOrFutureInt may be 10000. packageName := proptools.StringDefault(r.ravenwoodTestProperties.Package_name, "") instPackageName := proptools.StringDefault(r.ravenwoodTestProperties.Inst_package_name, "") + instClassName := proptools.StringDefault(r.ravenwoodTestProperties.Instrumentation_class, "") ctx.Build(pctx, android.BuildParams{ Rule: genManifestProperties, Description: "genManifestProperties", Output: propertiesOutputPath, Args: map[string]string{ - "targetSdkVersionInt": strconv.Itoa(targetSdkVersionInt), - "targetSdkVersionRaw": targetSdkVersion, - "packageName": packageName, - "instPackageName": instPackageName, + "targetSdkVersionInt": strconv.Itoa(targetSdkVersionInt), + "targetSdkVersionRaw": targetSdkVersion, + "packageName": packageName, + "instPackageName": instPackageName, + "instrumentationClass": instClassName, }, }) installProps := ctx.InstallFile(installPath, "ravenwood.properties", propertiesOutputPath) installDeps = append(installDeps, installProps) + // Copy data files + for _, data := range r.data { + installedData := ctx.InstallFile(installPath, data.Rel(), data) + installDeps = append(installDeps, installedData) + } + // Install our JAR with all dependencies ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...) @@ -338,6 +373,10 @@ func (r *ravenwoodLibgroup) DepsMutator(ctx android.BottomUpMutatorContext) { for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs.GetOrDefault(ctx, nil) { ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) } + + if r.Name() == ravenwoodRuntimeName { + ctx.AddVariationDependencies(nil, allAconfigModuleTag, aconfig.AllAconfigModule) + } } func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -355,11 +394,17 @@ func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContex names: jniDepNames, }) + install := func(to android.InstallPath, srcs ...android.Path) { + for _, s := range srcs { + ctx.InstallFile(to, s.Base(), s) + } + } + // Install our runtime into expected location for packaging installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) for _, lib := range r.ravenwoodLibgroupProperties.Libs { libModule := ctx.GetDirectDepProxyWithTag(lib, ravenwoodLibContentTag) - if libModule == nil { + if libModule.IsNil() { if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{lib}) } else { @@ -368,24 +413,50 @@ func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContex continue } libJar := android.OutputFileForModule(ctx, libModule, "") - ctx.InstallFile(installPath, lib+".jar", libJar) + ctx.InstallFile(installPath, libJar.Base(), libJar) } soInstallPath := android.PathForModuleInstall(ctx, r.BaseModuleName()).Join(ctx, getLibPath(r.forceArchType)) for _, jniLib := range jniLibs { - ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path) + install(soInstallPath, jniLib.path) } dataInstallPath := installPath.Join(ctx, "ravenwood-data") data := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Data) for _, file := range data { - ctx.InstallFile(dataInstallPath, file.Base(), file) + install(dataInstallPath, file) } fontsInstallPath := installPath.Join(ctx, "fonts") fonts := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Fonts) for _, file := range fonts { - ctx.InstallFile(fontsInstallPath, file.Base(), file) + install(fontsInstallPath, file) + } + + // Copy aconfig flag storage files. + if r.Name() == ravenwoodRuntimeName { + allAconfigFound := false + if allAconfig := ctx.GetDirectDepProxyWithTag(aconfig.AllAconfigModule, allAconfigModuleTag); !allAconfig.IsNil() { + aadi, ok := android.OtherModuleProvider(ctx, allAconfig, aconfig.AllAconfigDeclarationsInfoProvider) + if ok { + // Binary proto file and the text proto. + // We don't really use the text proto file, but having this would make debugging easier. + install(installPath.Join(ctx, "aconfig/metadata/aconfig/etc"), aadi.ParsedFlagsFile, aadi.TextProtoFlagsFile) + + // The "new" storage files. + install(installPath.Join(ctx, "aconfig/metadata/aconfig/maps"), aadi.StoragePackageMap, aadi.StorageFlagMap) + install(installPath.Join(ctx, "aconfig/metadata/aconfig/boot"), aadi.StorageFlagVal, aadi.StorageFlagInfo) + + allAconfigFound = true + } + } + if !allAconfigFound { + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{aconfig.AllAconfigModule}) + } else { + ctx.ModuleErrorf("missing dependency %q", aconfig.AllAconfigModule) + } + } } // Normal build should perform install steps diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go index d6493bcfa..55084bf22 100644 --- a/java/ravenwood_test.go +++ b/java/ravenwood_test.go @@ -15,6 +15,7 @@ package java import ( + "android/soong/aconfig" "runtime" "testing" @@ -27,6 +28,9 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( RegisterRavenwoodBuildComponents(ctx) }), android.FixtureAddTextFile("ravenwood/Android.bp", ` + all_aconfig_declarations { + name: "all_aconfig_declarations", + } cc_library_shared { name: "ravenwood-runtime-jni1", host_supported: true, @@ -55,6 +59,11 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( srcs: ["Services.java"], } java_library_static { + name: "ravenwood-runtime-extra", + stem: "runtime-extra", + srcs: ["Extra.java"], + } + java_library_static { name: "framework-rules.ravenwood", srcs: ["Rules.java"], } @@ -79,6 +88,7 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( libs: [ "framework-minus-apex.ravenwood", "framework-services.ravenwood", + "ravenwood-runtime-extra", ], jni_libs: [ "ravenwood-runtime-jni1", @@ -111,6 +121,7 @@ func TestRavenwoodRuntime(t *testing.T) { ctx := android.GroupFixturePreparers( PrepareForIntegrationTestWithJava, etc.PrepareForTestWithPrebuiltEtc, + aconfig.PrepareForTestWithAconfigBuildComponents, prepareRavenwoodRuntime, ).RunTest(t) @@ -124,11 +135,20 @@ func TestRavenwoodRuntime(t *testing.T) { runtime := ctx.ModuleForTests(t, "ravenwood-runtime", "android_common") runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-minus-apex.ravenwood.jar") runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-services.ravenwood.jar") + runtime.Output(installPathPrefix + "/ravenwood-runtime/runtime-extra.jar") runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so") 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") + + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/etc/all_aconfig_declarations.pb") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/etc/all_aconfig_declarations.textproto") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/maps/all_aconfig_declarations.package.map") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/maps/all_aconfig_declarations.flag.map") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/boot/all_aconfig_declarations.flag.info") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/boot/all_aconfig_declarations.val") + utils := ctx.ModuleForTests(t, "ravenwood-utils", "android_common") utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar") } @@ -142,6 +162,7 @@ func TestRavenwoodTest(t *testing.T) { ctx := android.GroupFixturePreparers( PrepareForIntegrationTestWithJava, etc.PrepareForTestWithPrebuiltEtc, + aconfig.PrepareForTestWithAconfigBuildComponents, prepareRavenwoodRuntime, ).RunTestWithBp(t, ` cc_library_shared { @@ -176,12 +197,17 @@ func TestRavenwoodTest(t *testing.T) { "jni-lib1", "ravenwood-runtime-jni2", ], + data: [ + "data/file1.txt", + "data2/sub/file2", + ], resource_apk: "app2", inst_resource_apk: "app3", sdk_version: "test_current", target_sdk_version: "34", package_name: "a.b.c", inst_package_name: "x.y.z", + instrumentation_class: "androidx.test.runner.AndroidJUnitRunner", } android_ravenwood_test { name: "ravenwood-test-empty", @@ -213,6 +239,8 @@ func TestRavenwoodTest(t *testing.T) { 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") + module.Output(installPathPrefix + "/ravenwood-test/data/file1.txt") + module.Output(installPathPrefix + "/ravenwood-test/data2/sub/file2") module = ctx.ModuleForTests(t, "ravenwood-test-empty", "android_common") module.Output(installPathPrefix + "/ravenwood-test-empty/ravenwood.properties") diff --git a/java/robolectric.go b/java/robolectric.go index 1d204a4e0..cee194777 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -149,6 +149,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) if proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) { extraTestRunnerOptions = append(extraTestRunnerOptions, tradefed.Option{Name: "java-flags", Value: "-Drobolectric.strict.mode=true"}) } + extraTestRunnerOptions = append(extraTestRunnerOptions, r.testProperties.Test_options.Test_runner_options...) var extraOptions []tradefed.Option var javaHome = ctx.Config().Getenv("ANDROID_JAVA_HOME") @@ -406,7 +407,7 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil { runtimeFromSourceModule := ctx.GetDirectDepProxyWithTag(String(r.props.Lib), libTag) - if runtimeFromSourceModule == nil { + if runtimeFromSourceModule.IsNil() { if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{String(r.props.Lib)}) } else { diff --git a/java/rro.go b/java/rro.go index 4ae8d7fc7..57b9da052 100644 --- a/java/rro.go +++ b/java/rro.go @@ -213,6 +213,11 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC Theme: r.Theme(), }) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: r.Certificate(), + Name: r.outputFile.Base(), + }) + ctx.SetOutputFiles([]android.Path{r.outputFile}, "") buildComplianceMetadata(ctx) @@ -261,6 +266,17 @@ func RuntimeResourceOverlayFactory() android.Module { android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.properties.Overrides) + + module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { + // Make this module product_specific by default. Keep this in sync with rroPartition() + if !ctx.DeviceSpecific() && !ctx.SocSpecific() && !ctx.SystemExtSpecific() { + proptools.AppendMatchingProperties(ctx.Module().GetProperties(), &struct { + Product_specific *bool + }{ + Product_specific: proptools.BoolPtr(true), + }, nil) + } + }) return module } @@ -358,12 +374,12 @@ func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android. } var rroDirs android.Paths // Get rro dirs of the base app - ctx.VisitDirectDepsWithTag(rroDepTag, func(m android.Module) { - aarDep, _ := m.(AndroidLibraryDependency) + ctx.VisitDirectDepsProxyWithTag(rroDepTag, func(m android.ModuleProxy) { + javaInfo, _ := android.OtherModuleProvider(ctx, m, JavaInfoProvider) if ctx.InstallInProduct() { - rroDirs = filterRRO(aarDep.RRODirsDepSet(), product) + rroDirs = filterRRO(javaInfo.AndroidLibraryDependencyInfo.RRODirsDepSet, product) } else { - rroDirs = filterRRO(aarDep.RRODirsDepSet(), device) + rroDirs = filterRRO(javaInfo.AndroidLibraryDependencyInfo.RRODirsDepSet, device) } }) @@ -421,6 +437,11 @@ func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android. OutputFile: signed, Certificate: a.certificate, }) + + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: a.certificate, + Name: signed.Base(), + }) } func (a *AutogenRuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { diff --git a/java/rro_test.go b/java/rro_test.go index 3e4fed51e..faf82af84 100644 --- a/java/rro_test.go +++ b/java/rro_test.go @@ -355,7 +355,7 @@ func TestRuntimeResourceOverlayFlagsPackages(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 link command expected to pass feature flags arguments", linkInFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) } diff --git a/java/sdk.go b/java/sdk.go index d676164e9..d1c7c0112 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -99,7 +99,7 @@ func systemModuleKind(sdkKind android.SdkKind, apiLevel android.ApiLevel) androi return systemModuleKind } -func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep { +func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext SdkVersionContext) sdkDep { sdkVersion := sdkContext.SdkVersion(ctx) if !sdkVersion.Valid() { ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.Raw) diff --git a/java/sdk_library.go b/java/sdk_library.go index 00ba8b2fb..4eec2ff35 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -17,9 +17,11 @@ package java import ( "errors" "fmt" + "maps" "path" "path/filepath" "reflect" + "slices" "sort" "strings" "sync" @@ -38,11 +40,11 @@ type scopeDependencyTag struct { apiScope *apiScope // Function for extracting appropriate path information from the dependency. - depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.Module) error + depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.ModuleProxy) error } // Extract tag specific information from the dependency. -func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) { +func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.ModuleProxy, paths *scopePaths) { err := tag.depInfoExtractor(paths, ctx, dep) if err != nil { ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error()) @@ -697,7 +699,7 @@ type scopePaths struct { latestRemovedApiPaths android.Paths } -func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.ModuleProxy) error { if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { paths.stubsHeaderPath = lib.HeaderJars paths.stubsImplPath = lib.ImplementationJars @@ -711,7 +713,7 @@ func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.Modul } } -func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.ModuleProxy) error { if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { paths.stubsHeaderPath = lib.HeaderJars if !ctx.Config().ReleaseHiddenApiExportableStubs() { @@ -726,7 +728,7 @@ func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx and } } -func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.ModuleProxy) error { if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { if ctx.Config().ReleaseHiddenApiExportableStubs() { paths.stubsImplPath = lib.ImplementationJars @@ -740,7 +742,7 @@ func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx and } } -func (paths *scopePaths) treatDepAsApiStubsProvider(ctx android.ModuleContext, dep android.Module, +func (paths *scopePaths) treatDepAsApiStubsProvider(ctx android.ModuleContext, dep android.ModuleProxy, action func(*DroidStubsInfo, *StubsSrcInfo) error) error { apiStubsProvider, ok := android.OtherModuleProvider(ctx, dep, DroidStubsInfoProvider) if !ok { @@ -755,7 +757,7 @@ func (paths *scopePaths) treatDepAsApiStubsProvider(ctx android.ModuleContext, d } func (paths *scopePaths) treatDepAsApiStubsSrcProvider( - ctx android.ModuleContext, dep android.Module, action func(provider *StubsSrcInfo) error) error { + ctx android.ModuleContext, dep android.ModuleProxy, action func(provider *StubsSrcInfo) error) error { if apiStubsProvider, ok := android.OtherModuleProvider(ctx, dep, StubsSrcInfoProvider); ok { err := action(&apiStubsProvider) if err != nil { @@ -797,7 +799,7 @@ func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider *S return err } -func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.ModuleProxy) error { stubsType := Everything if ctx.Config().ReleaseHiddenApiExportableStubs() { stubsType = Exportable @@ -807,7 +809,7 @@ func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext }) } -func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.ModuleProxy) error { stubsType := Everything if ctx.Config().ReleaseHiddenApiExportableStubs() { stubsType = Exportable @@ -819,7 +821,7 @@ func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx an }) } -func extractOutputPaths(ctx android.ModuleContext, dep android.Module) (android.Paths, error) { +func extractOutputPaths(ctx android.ModuleContext, dep android.ModuleProxy) (android.Paths, error) { var paths android.Paths if sourceFileProducer, ok := android.OtherModuleProvider(ctx, dep, android.SourceFilesInfoProvider); ok { paths = sourceFileProducer.Srcs @@ -829,13 +831,13 @@ func extractOutputPaths(ctx android.ModuleContext, dep android.Module) (android. } } -func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.ModuleProxy) error { outputPaths, err := extractOutputPaths(ctx, dep) paths.latestApiPaths = outputPaths return err } -func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.ModuleProxy) error { outputPaths, err := extractOutputPaths(ctx, dep) paths.latestRemovedApiPaths = outputPaths return err @@ -1022,6 +1024,12 @@ func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.Mod ExportableStubDexJarPaths: exportableStubPaths, RemovedTxtFiles: removedApiFilePaths, SharedLibrary: c.sharedLibrary(), + DoctagPaths: c.doctagPaths, + OnBootclasspathSince: c.commonSdkLibraryProperties.On_bootclasspath_since, + OnBootclasspathBefore: c.commonSdkLibraryProperties.On_bootclasspath_before, + MinDeviceSdk: c.commonSdkLibraryProperties.Min_device_sdk, + MaxDeviceSdk: c.commonSdkLibraryProperties.Max_device_sdk, + ImplLibProfileGuided: c.implLibraryInfo != nil && c.implLibraryInfo.ProfileGuided, } } @@ -1166,13 +1174,13 @@ func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(module android.M module.AddProperties(&e.sdkLibraryComponentProperties) } -// to satisfy SdkLibraryComponentDependency func (e *EmbeddableSdkLibraryComponent) SdkLibraryName() *string { return e.sdkLibraryComponentProperties.SdkLibraryName } -// to satisfy SdkLibraryComponentDependency -func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *string { +var SdkLibraryComponentDependencyInfoProvider = blueprint.NewMutatorProvider[SdkLibraryComponentDependencyInfo]("deps") + +type SdkLibraryComponentDependencyInfo struct { // For shared libraries, this is the same as the SDK library name. If a Java library or app // depends on a component library (e.g. a stub library) it still needs to know the name of the // run-time library and the corresponding module that provides the implementation. This name is @@ -1181,28 +1189,29 @@ func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *stri // // For non-shared SDK (component or not) libraries this returns `nil`, as they are not // <uses-library> and should not be added to the manifest or to CLC. - return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack + OptionalSdkLibraryImplementation *string + // The name of the java_sdk_library/_import module if this module was created by one. + SdkLibraryName *string } -// Implemented by modules that are (or possibly could be) a component of a java_sdk_library -// (including the java_sdk_library) itself. -type SdkLibraryComponentDependency interface { - UsesLibraryDependency - - // SdkLibraryName returns the name of the java_sdk_library/_import module. - SdkLibraryName() *string +func (e *EmbeddableSdkLibraryComponent) setComponentDependencyInfoProvider(ctx android.BottomUpMutatorContext) { + android.SetProvider(ctx, SdkLibraryComponentDependencyInfoProvider, SdkLibraryComponentDependencyInfo{ + OptionalSdkLibraryImplementation: e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack, + SdkLibraryName: e.sdkLibraryComponentProperties.SdkLibraryName, + }) +} - // The name of the implementation library for the optional SDK library or nil, if there isn't one. - OptionalSdkLibraryImplementation() *string +type ApiScopePathsInfo struct { + StubsImplPath android.Paths + CurrentApiFilePath android.OptionalPath + RemovedApiFilePath android.OptionalPath + StubsSrcJar android.OptionalPath + AnnotationsZip android.OptionalPath } -// Make sure that all the module types that are components of java_sdk_library/_import -// and which can be referenced (directly or indirectly) from an android app implement -// the SdkLibraryComponentDependency interface. -var _ SdkLibraryComponentDependency = (*Library)(nil) -var _ SdkLibraryComponentDependency = (*Import)(nil) -var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil) -var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil) +type ApiScopePropsInfo struct { + SdkVersion *string +} type SdkLibraryInfo struct { // GeneratingLibs is the names of the library modules that this sdk library @@ -1224,7 +1233,16 @@ type SdkLibraryInfo struct { // Whether if this can be used as a shared library. SharedLibrary bool - Prebuilt bool + Prebuilt bool + DistStem string + DoctagPaths android.Paths + OnBootclasspathSince *string + OnBootclasspathBefore *string + MinDeviceSdk *string + MaxDeviceSdk *string + ImplLibProfileGuided bool + ApiScopePaths map[string]ApiScopePathsInfo + ApiScopeProps map[string]ApiScopePropsInfo } var SdkLibraryInfoProvider = blueprint.NewProvider[SdkLibraryInfo]() @@ -1445,6 +1463,13 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { m += "Please see the documentation of the prebuilt_apis module type (and a usage example in prebuilts/sdk) for a convenient way to generate these." ctx.ModuleErrorf(m) } + + module.usesLibrary.deps(ctx, false) + + module.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) + libDeps := ctx.AddVariationDependencies(nil, usesLibStagingTag, module.properties.Libs...) + libDeps = append(libDeps, ctx.AddVariationDependencies(nil, usesLibStagingTag, module.sdkLibraryProperties.Impl_only_libs...)...) + module.usesLibrary.depsFromLibs(ctx, libDeps) } func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -1505,6 +1530,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) module.bootDexJarPath = module.implLibraryInfo.BootDexJarPath module.uncompressDexState = module.implLibraryInfo.UncompressDexState module.active = module.implLibraryInfo.Active + module.classLoaderContexts = module.usesLibrary.classLoaderContextForUsesLibDeps(ctx) } module.outputFile = module.implLibraryInfo.OutputFile @@ -1519,7 +1545,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // Properties required for Library.AndroidMkEntries module.logtagsSrcs = module.implLibraryInfo.LogtagsSrcs module.dexpreopter.builtInstalled = module.implLibraryInfo.BuiltInstalled - module.jacocoReportClassesFile = module.implLibraryInfo.JacocoReportClassesFile + module.jacocoInfo = module.implLibraryInfo.JacocoInfo module.dexer.proguardDictionary = module.implLibraryInfo.ProguardDictionary module.dexer.proguardUsageZip = module.implLibraryInfo.ProguardUsageZip module.linter.reports = module.implLibraryInfo.LinterReports @@ -1532,9 +1558,9 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) module.hostdexInstallFile = module.implLibraryInfo.HostdexInstallFile } - if installFilesInfo, ok := android.OtherModuleProvider(ctx, implLib, android.InstallFilesProvider); ok { - if installFilesInfo.CheckbuildTarget != nil { - ctx.CheckbuildFile(installFilesInfo.CheckbuildTarget) + if buildTargetsInfo, ok := android.OtherModuleProvider(ctx, implLib, android.ModuleBuildTargetsProvider); ok { + if buildTargetsInfo.CheckbuildTarget != nil { + ctx.CheckbuildFile(buildTargetsInfo.CheckbuildTarget) } } } @@ -1581,14 +1607,47 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) } javaInfo := &JavaInfo{ - JacocoReportClassesFile: module.jacocoReportClassesFile, + JacocoInfo: module.jacocoInfo, + CompileDex: module.dexProperties.Compile_dex, } setExtraJavaInfo(ctx, ctx.Module(), javaInfo) android.SetProvider(ctx, JavaInfoProvider, javaInfo) sdkLibInfo.GeneratingLibs = generatingLibs sdkLibInfo.Prebuilt = false + sdkLibInfo.DistStem = module.distStem() + if module.scopePaths != nil { + sdkLibInfo.ApiScopePaths = make(map[string]ApiScopePathsInfo) + for k, v := range module.scopePaths { + sdkLibInfo.ApiScopePaths[k.name] = ApiScopePathsInfo{ + StubsImplPath: v.stubsImplPath, + CurrentApiFilePath: v.currentApiFilePath, + RemovedApiFilePath: v.removedApiFilePath, + StubsSrcJar: v.stubsSrcJar, + AnnotationsZip: v.annotationsZip, + } + } + } + if module.scopeToProperties != nil { + sdkLibInfo.ApiScopeProps = make(map[string]ApiScopePropsInfo) + for k, v := range module.scopeToProperties { + sdkLibInfo.ApiScopeProps[k.name] = ApiScopePropsInfo{ + SdkVersion: v.Sdk_version, + } + } + } android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo) + + android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{ + PermittedPackages: module.PermittedPackagesForUpdatableBootJars(), + }) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if module.implementationAndResourcesJar != nil { + moduleInfoJSON.ClassesJar = []string{module.implementationAndResourcesJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func setOutputFilesFromJavaInfo(ctx android.ModuleContext, info *JavaInfo) { @@ -1630,12 +1689,17 @@ func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string { // Get the sdk version for use when compiling the stubs library. func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.EarlyModuleContext, apiScope *apiScope) string { - scopeProperties := module.scopeToProperties[apiScope] - if scopeProperties.Sdk_version != nil { - return proptools.String(scopeProperties.Sdk_version) + return getSdkVersionForStubsLibrary(mctx, apiScope, module.scopeToProperties[apiScope].Sdk_version, + android.SdkContext(&module.Library)) +} + +func getSdkVersionForStubsLibrary(mctx android.EarlyModuleContext, apiScope *apiScope, + sdkVersion *string, sdkContext SdkVersionContext) string { + if sdkVersion != nil { + return proptools.String(sdkVersion) } - sdkDep := decodeSdkDep(mctx, android.SdkContext(&module.Library)) + sdkDep := decodeSdkDep(mctx, sdkContext) if sdkDep.hasStandardLibs() { // If building against a standard sdk then use the sdk version appropriate for the scope. return apiScope.sdkVersion @@ -1797,11 +1861,17 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont panic(fmt.Sprintf("script file %s doesn't exist", script)) } + env_msg := "" + if mctx.Config().GetBuildFlagBool("RELEASE_SRC_DIR_IS_READ_ONLY") { + env_msg = "BUILD_BROKEN_SRC_DIR_IS_WRITABLE=true " + } + mctx.ModuleErrorf("One or more current api files are missing. "+ "You can update them by:\n"+ - "%s %q %s && m update-api", + "%s %q %s && %sm update-api", script, filepath.Join(mctx.ModuleDir(), apiDir), - strings.Join(generatedScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " ")) + strings.Join(generatedScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " "), + env_msg) return } @@ -2076,6 +2146,12 @@ func (module *SdkLibraryImport) BaseModuleName() string { return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name()) } +func (module *SdkLibraryImport) sortedApiScopes() []*apiScope { + return slices.SortedFunc(maps.Keys(module.scopeProperties), func(a, b *apiScope) int { + return strings.Compare(a.name, b.name) + }) +} + func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) { // If the build is configured to use prebuilts then force this to be preferred. @@ -2083,7 +2159,8 @@ func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHo module.prebuilt.ForcePrefer() } - for apiScope, scopeProperties := range module.scopeProperties { + for _, apiScope := range module.sortedApiScopes() { + scopeProperties := module.scopeProperties[apiScope] if len(scopeProperties.Jars) == 0 { continue } @@ -2108,7 +2185,8 @@ func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHo // 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) { - for apiScope, scopeProperties := range module.scopeProperties { + for _, apiScope := range module.sortedApiScopes() { + scopeProperties := module.scopeProperties[apiScope] if len(scopeProperties.Jars) == 0 { continue } @@ -2136,6 +2214,8 @@ func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) ctx.AddDependency(module, xmlPermissionsFileTag, xmlPermissionsModuleName) } } + + module.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } var _ android.ApexModule = (*SdkLibraryImport)(nil) @@ -2202,7 +2282,8 @@ 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 { + for _, apiScope := range module.sortedApiScopes() { + scopeProperties := module.scopeProperties[apiScope] if len(scopeProperties.Jars) == 0 { continue } @@ -2243,7 +2324,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo javaInfo := &JavaInfo{} if module.implLibraryInfo != nil { - javaInfo.JacocoReportClassesFile = module.implLibraryInfo.JacocoReportClassesFile + javaInfo.JacocoInfo = module.implLibraryInfo.JacocoInfo } setExtraJavaInfo(ctx, ctx.Module(), javaInfo) @@ -2283,16 +2364,7 @@ func (module *SdkLibraryImport) ClassLoaderContexts() dexpreopt.ClassLoaderConte return nil } -// to satisfy apex.javaDependency interface -func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { - if module.implLibraryInfo == nil { - return nil - } else { - return module.implLibraryInfo.JacocoReportClassesFile - } -} - -// to satisfy apex.javaDependency interface +// to satisfy apex.javaModule interface func (module *SdkLibraryImport) Stem() string { return module.BaseModuleName() } @@ -2341,9 +2413,9 @@ func (s *sdkLibrarySdkMemberType) AddDependencies(ctx android.SdkDependencyConte ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*SdkLibrary) - return ok +func (s *sdkLibrarySdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + info, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider) + return ok && !info.Prebuilt } func (s *sdkLibrarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { @@ -2436,49 +2508,70 @@ type scopeProperties struct { SdkVersion string } -func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - sdk := variant.(*SdkLibrary) +type SdkVersionContext interface { + SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec + SystemModules() string +} + +type SdkVersionContextProviderImpl struct { + javaInfo *JavaInfo +} + +func (s *SdkVersionContextProviderImpl) SdkVersion(_ android.EarlyModuleContext) android.SdkSpec { + return s.javaInfo.SdkVersion +} +func (s *SdkVersionContextProviderImpl) SystemModules() string { + return s.javaInfo.SystemModules +} + +func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + mctx := ctx.SdkModuleContext() + javaInfo := android.OtherModulePointerProviderOrDefault(mctx, variant, JavaInfoProvider) + libraryInfo := android.OtherModuleProviderOrDefault(mctx, variant, JavaLibraryInfoProvider) + sdkInfo := android.OtherModuleProviderOrDefault(mctx, variant, SdkLibraryInfoProvider) // Copy the stem name for files in the sdk snapshot. - s.Stem = sdk.distStem() + s.Stem = sdkInfo.DistStem s.Scopes = make(map[*apiScope]*scopeProperties) for _, apiScope := range AllApiScopes { - paths := sdk.findScopePaths(apiScope) - if paths == nil { + paths, ok := sdkInfo.ApiScopePaths[apiScope.name] + if !ok { continue } - jars := paths.stubsImplPath + jars := paths.StubsImplPath if len(jars) > 0 { properties := scopeProperties{} properties.Jars = jars - properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope) - properties.StubsSrcJar = paths.stubsSrcJar.Path() - if paths.currentApiFilePath.Valid() { - properties.CurrentApiFile = paths.currentApiFilePath.Path() + properties.SdkVersion = getSdkVersionForStubsLibrary(mctx, apiScope, sdkInfo.ApiScopeProps[apiScope.name].SdkVersion, + &SdkVersionContextProviderImpl{javaInfo}) + + properties.StubsSrcJar = paths.StubsSrcJar.Path() + if paths.CurrentApiFilePath.Valid() { + properties.CurrentApiFile = paths.CurrentApiFilePath.Path() } - if paths.removedApiFilePath.Valid() { - properties.RemovedApiFile = paths.removedApiFilePath.Path() + if paths.RemovedApiFilePath.Valid() { + properties.RemovedApiFile = paths.RemovedApiFilePath.Path() } // The annotations zip is only available for modules that set annotations_enabled: true. - if paths.annotationsZip.Valid() { - properties.AnnotationsZip = paths.annotationsZip.Path() + if paths.AnnotationsZip.Valid() { + properties.AnnotationsZip = paths.AnnotationsZip.Path() } s.Scopes[apiScope] = &properties } } - s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary()) - s.Compile_dex = sdk.dexProperties.Compile_dex - s.Doctag_paths = sdk.doctagPaths - s.Permitted_packages = sdk.PermittedPackagesForUpdatableBootJars() - s.On_bootclasspath_since = sdk.commonSdkLibraryProperties.On_bootclasspath_since - s.On_bootclasspath_before = sdk.commonSdkLibraryProperties.On_bootclasspath_before - s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk - s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk + s.Shared_library = proptools.BoolPtr(sdkInfo.SharedLibrary) + s.Compile_dex = javaInfo.CompileDex + s.Doctag_paths = sdkInfo.DoctagPaths + s.Permitted_packages = libraryInfo.PermittedPackages + s.On_bootclasspath_since = sdkInfo.OnBootclasspathSince + s.On_bootclasspath_before = sdkInfo.OnBootclasspathBefore + s.Min_device_sdk = sdkInfo.MinDeviceSdk + s.Max_device_sdk = sdkInfo.MaxDeviceSdk - if sdk.implLibraryInfo != nil && sdk.implLibraryInfo.ProfileGuided { + if sdkInfo.ImplLibProfileGuided { s.DexPreoptProfileGuided = proptools.BoolPtr(true) } } diff --git a/java/sdk_library_internal.go b/java/sdk_library_internal.go index f5feabeb4..2d27c42f6 100644 --- a/java/sdk_library_internal.go +++ b/java/sdk_library_internal.go @@ -20,7 +20,9 @@ import ( "strings" "android/soong/android" + "android/soong/dexpreopt" "android/soong/etc" + "android/soong/java/config" "github.com/google/blueprint/proptools" ) @@ -168,6 +170,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) &module.dexpreoptProperties, &module.linter.properties, &module.overridableProperties, + &module.usesLibrary.usesLibraryProperties, &props, module.sdkComponentPropertiesForChildLibrary(), } @@ -581,7 +584,9 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { Min_device_sdk *string Max_device_sdk *string Sdk_library_min_api_level *string - Uses_libs_dependencies proptools.Configurable[[]string] + Uses_libs proptools.Configurable[[]string] + Libs []string + Impl_only_libs []string }{ Name: proptools.StringPtr(module.xmlPermissionsModuleName()), Enabled: module.EnabledProperty(), @@ -592,7 +597,9 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { 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.Clone(), + Uses_libs: module.usesLibraryProperties.Uses_libs.Clone(), + Libs: android.RemoveListFromList(module.properties.Libs, config.FrameworkLibraries), + Impl_only_libs: module.sdkLibraryProperties.Impl_only_libs, } mctx.CreateModule(sdkLibraryXmlFactory, &props) @@ -716,6 +723,8 @@ type sdkLibraryXml struct { installDirPath android.InstallPath hideApexVariantFromMake bool + + usesLibrary } type sdkLibraryXmlProperties struct { @@ -754,10 +763,11 @@ type sdkLibraryXmlProperties struct { // 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 proptools.Configurable[[]string] + // List of java libraries that will be in the classpath. + Libs []string `android:"arch_variant"` + + // List of Java libraries that will be in the classpath when building the implementation lib. + Impl_only_libs []string `android:"arch_variant"` } // java_sdk_library_xml builds the permission xml file for a java_sdk_library. @@ -765,7 +775,7 @@ type sdkLibraryXmlProperties struct { func sdkLibraryXmlFactory() android.Module { module := &sdkLibraryXml{} - module.AddProperties(&module.properties) + module.AddProperties(&module.properties, &module.usesLibrary.usesLibraryProperties) android.InitApexModule(module) android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) @@ -801,7 +811,10 @@ func (module *sdkLibraryXml) ApexAvailableFor() []string { } func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { - // do nothing + module.usesLibrary.deps(ctx, false) + libDeps := ctx.AddVariationDependencies(nil, usesLibStagingTag, module.properties.Libs...) + libDeps = append(libDeps, ctx.AddVariationDependencies(nil, usesLibStagingTag, module.properties.Impl_only_libs...)...) + module.usesLibrary.depsFromLibs(ctx, libDeps) } var _ android.ApexModule = (*sdkLibraryXml)(nil) @@ -865,8 +878,13 @@ func formattedOptionalAttribute(attrName string, value *string) string { return fmt.Sprintf(" %s=\"%s\"\n", attrName, *value) } -func formattedDependenciesAttribute(dependencies []string) string { - if dependencies == nil { +func (module *sdkLibraryXml) formattedDependenciesAttribute(ctx android.ModuleContext) string { + classLoaderContexts := module.usesLibrary.classLoaderContextForUsesLibDeps(ctx) + dependencies := make([]string, 0, len(classLoaderContexts[dexpreopt.AnySdkVersion])) + for _, dep := range classLoaderContexts[dexpreopt.AnySdkVersion] { + dependencies = append(dependencies, dep.Name) + } + if len(dependencies) == 0 { return "" } return fmt.Sprintf(" dependency=\"%s\"\n", strings.Join(dependencies, ":")) @@ -881,7 +899,7 @@ func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) stri 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.GetOrDefault(ctx, nil)) + dependenciesAttr := module.formattedDependenciesAttribute(ctx) // <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 diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 6d27e54d0..1f4b57e7d 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -180,11 +180,11 @@ func TestJavaSdkLibrary(t *testing.T) { fooImplDexJar := result.ModuleForTests(t, "foo.impl", "android_common").Rule("d8") // tests if kotlinc generated files are NOT excluded from output of foo.impl. - android.AssertStringDoesNotContain(t, "foo.impl dex", fooImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") + android.AssertStringDoesNotContain(t, "foo.impl dex", fooImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/**/*.kotlin_module") barImplDexJar := result.ModuleForTests(t, "bar.impl", "android_common").Rule("d8") // tests if kotlinc generated files are excluded from output of bar.impl. - android.AssertStringDoesContain(t, "bar.impl dex", barImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") + android.AssertStringDoesContain(t, "bar.impl dex", barImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/**/*.kotlin_module") } func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { diff --git a/java/system_modules.go b/java/system_modules.go index e955aec15..5ced86efc 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -29,6 +29,8 @@ import ( // file will produce the rules necessary to convert each unique set of bootclasspath jars into // system modules in a runtime image using the jmod and jlink tools. +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { RegisterSystemModulesBuildComponents(android.InitRegistrationContext) @@ -121,6 +123,7 @@ func SystemModulesFactory() android.Module { return module } +// @auto-generate: gob type SystemModulesProviderInfo struct { // The aggregated header jars from all jars specified in the libs property. // Used when system module is added as a dependency to bootclasspath. @@ -131,6 +134,8 @@ type SystemModulesProviderInfo struct { // depset of header jars for this module and all transitive static dependencies TransitiveStaticLibsHeaderJars depset.DepSet[android.Path] + Prebuilt bool + Libs []string } var SystemModulesProvider = blueprint.NewProvider[*SystemModulesProviderInfo]() @@ -150,11 +155,21 @@ type SystemModulesProperties struct { Libs []string } +func (system *systemModulesImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { + info := system.commonBuildActions(ctx) + info.Prebuilt = true + android.SetProvider(ctx, SystemModulesProvider, info) +} + func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) { + android.SetProvider(ctx, SystemModulesProvider, system.commonBuildActions(ctx)) +} + +func (system *SystemModules) commonBuildActions(ctx android.ModuleContext) *SystemModulesProviderInfo { var jars android.Paths var transitiveStaticLibsHeaderJars []depset.DepSet[android.Path] - ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) { + ctx.VisitDirectDepsProxyWithTag(systemModulesLibsTag, func(module android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { jars = append(jars, dep.HeaderJars...) transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars) @@ -163,12 +178,13 @@ func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleConte system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars) - android.SetProvider(ctx, SystemModulesProvider, &SystemModulesProviderInfo{ + return &SystemModulesProviderInfo{ HeaderJars: jars, OutputDir: system.outputDir, OutputDirDeps: system.outputDeps, TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, nil, transitiveStaticLibsHeaderJars), - }) + Libs: system.properties.Libs, + } } // ComponentDepsMutator is called before prebuilt modules without a corresponding source module are @@ -275,12 +291,11 @@ func (mt *systemModulesSdkMemberType) AddDependencies(ctx android.SdkDependencyC ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (mt *systemModulesSdkMemberType) IsInstance(module android.Module) bool { - if _, ok := module.(*SystemModules); ok { +func (mt *systemModulesSdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + if info, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok { // A prebuilt system module cannot be added as a member of an sdk because the source and // snapshot instances would conflict. - _, ok := module.(*systemModulesImport) - return !ok + return !info.Prebuilt } return false } @@ -299,9 +314,8 @@ func (mt *systemModulesSdkMemberType) CreateVariantPropertiesStruct() android.Sd return &systemModulesInfoProperties{} } -func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - systemModule := variant.(*SystemModules) - p.Libs = systemModule.properties.Libs +func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + p.Libs = android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, SystemModulesProvider).Libs } func (p *systemModulesInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { diff --git a/java/system_modules_gob_enc.go b/java/system_modules_gob_enc.go new file mode 100644 index 000000000..7585318b4 --- /dev/null +++ b/java/system_modules_gob_enc.go @@ -0,0 +1,137 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package java + +import ( + "android/soong/android" + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + SystemModulesProviderInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SystemModulesProviderInfo) }) +} + +func (r SystemModulesProviderInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.HeaderJars))); err != nil { + return err + } + for val1 := 0; val1 < len(r.HeaderJars); val1++ { + if err = gobtools.EncodeInterface(buf, r.HeaderJars[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeInterface(buf, r.OutputDir); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.OutputDirDeps))); err != nil { + return err + } + for val2 := 0; val2 < len(r.OutputDirDeps); val2++ { + if err = gobtools.EncodeInterface(buf, r.OutputDirDeps[val2]); err != nil { + return err + } + } + + if err = r.TransitiveStaticLibsHeaderJars.EncodeInterface(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Prebuilt); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Libs))); err != nil { + return err + } + for val3 := 0; val3 < len(r.Libs); val3++ { + if err = gobtools.EncodeString(buf, r.Libs[val3]); err != nil { + return err + } + } + return err +} + +func (r *SystemModulesProviderInfo) Decode(buf *bytes.Reader) error { + var err error + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.HeaderJars = make([]android.Path, val3) + for val4 := 0; val4 < int(val3); val4++ { + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.HeaderJars[val4] = nil + } else { + r.HeaderJars[val4] = val6.(android.Path) + } + } + } + + if val8, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val8 == nil { + r.OutputDir = nil + } else { + r.OutputDir = val8.(android.Path) + } + + var val11 int32 + err = gobtools.DecodeSimple[int32](buf, &val11) + if err != nil { + return err + } + if val11 > 0 { + r.OutputDirDeps = make([]android.Path, val11) + for val12 := 0; val12 < int(val11); val12++ { + if val14, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val14 == nil { + r.OutputDirDeps[val12] = nil + } else { + r.OutputDirDeps[val12] = val14.(android.Path) + } + } + } + + if err = r.TransitiveStaticLibsHeaderJars.DecodeInterface(buf); err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Prebuilt) + if err != nil { + return err + } + + var val18 int32 + err = gobtools.DecodeSimple[int32](buf, &val18) + if err != nil { + return err + } + if val18 > 0 { + r.Libs = make([]string, val18) + for val19 := 0; val19 < int(val18); val19++ { + err = gobtools.DecodeString(buf, &r.Libs[val19]) + if err != nil { + return err + } + } + } + + return err +} + +var SystemModulesProviderInfoGobRegId int16 + +func (r SystemModulesProviderInfo) GetTypeId() int16 { + return SystemModulesProviderInfoGobRegId +} diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index a60f6b82c..345090067 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -97,6 +97,13 @@ type SystemServerClasspathModule struct { var _ android.ApexModule = (*SystemServerClasspathModule)(nil) +type SystemServerClasspathInfo struct { + Contents []string + StandaloneContents []string +} + +var SystemServerClasspathInfoProvider = blueprint.NewProvider[SystemServerClasspathInfo]() + func (m *SystemServerClasspathModule) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { return android.MinApiLevel } @@ -139,6 +146,11 @@ func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.Mo classpathJars = append(classpathJars, standaloneClasspathJars...) s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) s.setPartitionInfoOfLibraries(ctx) + + android.SetProvider(ctx, SystemServerClasspathInfoProvider, SystemServerClasspathInfo{ + Contents: s.properties.Contents.GetOrDefault(ctx, nil), + StandaloneContents: s.properties.Standalone_contents.GetOrDefault(ctx, nil), + }) } // Map of java library name to their install partition. @@ -152,8 +164,9 @@ var LibraryNameToPartitionInfoProvider = blueprint.NewProvider[LibraryNameToPart func (s *SystemServerClasspathModule) setPartitionInfoOfLibraries(ctx android.ModuleContext) { libraryNameToPartition := map[string]string{} - ctx.VisitDirectDepsWithTag(systemServerClasspathFragmentContentDepTag, func(m android.Module) { - libraryNameToPartition[m.Name()] = m.PartitionTag(ctx.DeviceConfig()) + ctx.VisitDirectDepsProxyWithTag(systemServerClasspathFragmentContentDepTag, func(m android.ModuleProxy) { + info := android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + libraryNameToPartition[m.Name()] = info.PartitionTag }) android.SetProvider(ctx, LibraryNameToPartitionInfoProvider, LibraryNameToPartitionInfo{ LibraryNameToPartition: libraryNameToPartition, @@ -214,10 +227,10 @@ func (systemServerClasspathFragmentContentDependencyTag) ReplaceSourceWithPrebui // SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if // they were specified using java_systemserver_libs or java_sdk_libs. -func (b systemServerClasspathFragmentContentDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType { +func (b systemServerClasspathFragmentContentDependencyTag) SdkMemberType(ctx android.ModuleContext, child android.ModuleProxy) android.SdkMemberType { // If the module is a java_sdk_library then treat it as if it was specified in the java_sdk_libs // property, otherwise treat if it was specified in the java_systemserver_libs property. - if javaSdkLibrarySdkMemberType.IsInstance(child) { + if javaSdkLibrarySdkMemberType.IsInstance(ctx, child) { return javaSdkLibrarySdkMemberType } @@ -278,8 +291,8 @@ func (s *systemServerClasspathFragmentMemberType) AddDependencies(ctx android.Sd ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (s *systemServerClasspathFragmentMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*SystemServerClasspathModule) +func (s *systemServerClasspathFragmentMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + _, ok := android.OtherModuleProvider(ctx, module, SystemServerClasspathInfoProvider) return ok } @@ -305,11 +318,11 @@ type systemServerClasspathFragmentSdkMemberProperties struct { Standalone_contents []string } -func (s *systemServerClasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - module := variant.(*SystemServerClasspathModule) +func (s *systemServerClasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + module := android.OtherModuleProviderOrDefault(ctx.SdkModuleContext(), variant, SystemServerClasspathInfoProvider) - s.Contents = module.properties.Contents.GetOrDefault(ctx.SdkModuleContext(), nil) - s.Standalone_contents = module.properties.Standalone_contents.GetOrDefault(ctx.SdkModuleContext(), nil) + s.Contents = module.Contents + s.Standalone_contents = module.StandaloneContents } func (s *systemServerClasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { diff --git a/java/testing.go b/java/testing.go index c5a0ef390..3989d1987 100644 --- a/java/testing.go +++ b/java/testing.go @@ -588,7 +588,7 @@ func getModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant t.Helper() module := ctx.ModuleForTests(t, name, variant).Module() deps := []string{} - ctx.VisitDirectDeps(module, func(m blueprint.Module) { + ctx.VisitDirectDepsProxies(module, func(m android.ModuleProxy) { deps = append(deps, m.Name()) }) return android.SortedUniqueStrings(deps) @@ -654,9 +654,9 @@ func CheckClasspathFragmentProtoContentInfoProvider(t *testing.T, result *androi func CheckPlatformBootclasspathDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) { t.Helper() platformBootclasspath := ctx.ModuleForTests(t, name, variant).Module().(*platformBootclasspathModule) - modules := []android.Module{} - ctx.VisitDirectDeps(platformBootclasspath, func(m blueprint.Module) { - modules = append(modules, m.(android.Module)) + modules := []android.ModuleProxy{} + ctx.VisitDirectDepsProxies(platformBootclasspath, func(m android.ModuleProxy) { + modules = append(modules, m) }) pairs := apexNamePairsFromModules(ctx, modules, platformBootclasspath.libraryToApex) @@ -664,7 +664,7 @@ func CheckPlatformBootclasspathDependencies(t *testing.T, ctx *android.TestConte } // apexNamePairsFromModules returns the apex:module pair for the supplied modules. -func apexNamePairsFromModules(ctx *android.TestContext, modules []android.Module, modulesToApex map[android.Module]string) []string { +func apexNamePairsFromModules(ctx *android.TestContext, modules []android.ModuleProxy, modulesToApex map[android.ModuleProxy]string) []string { pairs := []string{} for _, module := range modules { pairs = append(pairs, apexNamePairFromModule(ctx, module, modulesToApex)) @@ -673,7 +673,7 @@ func apexNamePairsFromModules(ctx *android.TestContext, modules []android.Module } // ApexFragmentPairsFromModules returns the apex:fragment pair for the supplied fragments. -func ApexFragmentPairsFromModules(ctx *android.TestContext, fragments []android.Module, apexNameToFragment map[string]android.Module) []string { +func ApexFragmentPairsFromModules(ctx *android.TestContext, fragments []android.ModuleProxy, apexNameToFragment map[string]android.ModuleProxy) []string { pairs := []string{} for _, fragment := range fragments { found := false @@ -690,7 +690,7 @@ func ApexFragmentPairsFromModules(ctx *android.TestContext, fragments []android. return pairs } -func apexNamePairFromModule(ctx *android.TestContext, module android.Module, modulesToApex map[android.Module]string) string { +func apexNamePairFromModule(ctx *android.TestContext, module android.ModuleProxy, modulesToApex map[android.ModuleProxy]string) string { name := module.Name() apex := modulesToApex[module] if apex == "" { |
