diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/Android.bp | 2 | ||||
| -rw-r--r-- | java/aar.go | 22 | ||||
| -rw-r--r-- | java/androidmk.go | 16 | ||||
| -rwxr-xr-x | java/app.go | 94 | ||||
| -rw-r--r-- | java/app_import.go | 11 | ||||
| -rw-r--r-- | java/app_import_test.go | 149 | ||||
| -rw-r--r-- | java/app_test.go | 132 | ||||
| -rw-r--r-- | java/base.go | 50 | ||||
| -rw-r--r-- | java/builder.go | 135 | ||||
| -rw-r--r-- | java/config/config.go | 51 | ||||
| -rw-r--r-- | java/config/error_prone.go | 24 | ||||
| -rw-r--r-- | java/config/kotlin.go | 6 | ||||
| -rw-r--r-- | java/dex.go | 11 | ||||
| -rw-r--r-- | java/dex_test.go | 103 | ||||
| -rw-r--r-- | java/droidstubs.go | 12 | ||||
| -rw-r--r-- | java/hiddenapi_modular.go | 62 | ||||
| -rw-r--r-- | java/java.go | 209 | ||||
| -rw-r--r-- | java/java_test.go | 2 | ||||
| -rw-r--r-- | java/jdeps.go | 2 | ||||
| -rw-r--r-- | java/kotlin.go | 63 | ||||
| -rw-r--r-- | java/kotlin_test.go | 78 | ||||
| -rw-r--r-- | java/lint.go | 22 | ||||
| -rw-r--r-- | java/plugin.go | 29 | ||||
| -rw-r--r-- | java/sdk_library.go | 8 | ||||
| -rw-r--r-- | java/testing.go | 4 |
25 files changed, 845 insertions, 452 deletions
diff --git a/java/Android.bp b/java/Android.bp index c0629414e..df0d1eb3d 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -15,6 +15,7 @@ bootstrap_go_package { "soong-dexpreopt", "soong-genrule", "soong-java-config", + "soong-provenance", "soong-python", "soong-remoteexec", "soong-tradefed", @@ -81,6 +82,7 @@ bootstrap_go_package { "app_test.go", "bootclasspath_fragment_test.go", "device_host_converter_test.go", + "dex_test.go", "dexpreopt_test.go", "dexpreopt_bootjars_test.go", "droiddoc_test.go", diff --git a/java/aar.go b/java/aar.go index 8e1025361..00ff7e774 100644 --- a/java/aar.go +++ b/java/aar.go @@ -598,16 +598,26 @@ func AndroidLibraryFactory() android.Module { // AAR (android library) prebuilts // +// Properties for android_library_import type AARImportProperties struct { + // ARR (android library prebuilt) filepath. Exactly one ARR is required. Aars []string `android:"path"` - - Sdk_version *string + // If not blank, set to the version of the sdk to compile against. + // Defaults to private. + // Values are of one of the following forms: + // 1) numerical API level, "current", "none", or "core_platform" + // 2) An SDK kind with an API level: "<sdk kind>_<API level>" + // See build/soong/android/sdk_version.go for the complete and up to date list of SDK kinds. + // If the SDK kind is empty, it will be set to public + Sdk_version *string + // If not blank, set the minimum version of the sdk that the compiled artifacts will run against. + // Defaults to sdk_version if not set. See sdk_version for possible values. Min_sdk_version *string - + // List of java static libraries that the included ARR (android library prebuilts) has dependencies to. Static_libs []string - Libs []string - - // if set to true, run Jetifier against .aar file. Defaults to false. + // List of java libraries that the included ARR (android library prebuilts) has dependencies to. + Libs []string + // If set to true, run Jetifier against .aar file. Defaults to false. Jetifier *bool } diff --git a/java/androidmk.go b/java/androidmk.go index b930441f3..80b828d45 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -409,22 +409,6 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports) }, }, - ExtraFooters: []android.AndroidMkExtraFootersFunc{ - func(w io.Writer, name, prefix, moduleDir string) { - if app.noticeOutputs.Merged.Valid() { - fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", - app.installApkName, app.noticeOutputs.Merged.String(), app.installApkName+"_NOTICE") - } - if app.noticeOutputs.TxtOutput.Valid() { - fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", - app.installApkName, app.noticeOutputs.TxtOutput.String(), app.installApkName+"_NOTICE.txt") - } - if app.noticeOutputs.HtmlOutput.Valid() { - fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", - app.installApkName, app.noticeOutputs.HtmlOutput.String(), app.installApkName+"_NOTICE.html") - } - }, - }, }} } diff --git a/java/app.go b/java/app.go index 96fd61ad9..2b52eab15 100755 --- a/java/app.go +++ b/java/app.go @@ -19,7 +19,6 @@ package java import ( "path/filepath" - "sort" "strings" "github.com/google/blueprint" @@ -164,8 +163,6 @@ type AndroidApp struct { additionalAaptFlags []string - noticeOutputs android.NoticeOutputs - overriddenManifestPackageName string android.ApexBundleDepsInfo @@ -523,53 +520,6 @@ func (a *AndroidApp) JNISymbolsInstalls(installPath string) android.RuleBuilderI return jniSymbols } -func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext) { - // Collect NOTICE files from all dependencies. - seenModules := make(map[android.Module]bool) - noticePathSet := make(map[android.Path]bool) - - ctx.WalkDeps(func(child android.Module, parent android.Module) bool { - // Have we already seen this? - if _, ok := seenModules[child]; ok { - return false - } - seenModules[child] = true - - // Skip host modules. - if child.Target().Os.Class == android.Host { - return false - } - - paths := child.(android.Module).NoticeFiles() - if len(paths) > 0 { - for _, path := range paths { - noticePathSet[path] = true - } - } - return true - }) - - // If the app has one, add it too. - if len(a.NoticeFiles()) > 0 { - for _, path := range a.NoticeFiles() { - noticePathSet[path] = true - } - } - - if len(noticePathSet) == 0 { - return - } - var noticePaths []android.Path - for path := range noticePathSet { - noticePaths = append(noticePaths, path) - } - sort.Slice(noticePaths, func(i, j int) bool { - return noticePaths[i].String() < noticePaths[j].String() - }) - - a.noticeOutputs = android.BuildNoticeOutput(ctx, a.installDir, a.installApkName+".apk", noticePaths) -} - // Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it // isn't a cert module reference. Also checks and enforces system cert restriction if applicable. func processMainCert(m android.ModuleBase, certPropValue string, certificates []Certificate, ctx android.ModuleContext) []Certificate { @@ -636,9 +586,16 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } a.onDeviceDir = android.InstallPathToOnDevicePath(ctx, a.installDir) - a.noticeBuildActions(ctx) if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") { - a.aapt.noticeFile = a.noticeOutputs.HtmlGzOutput + noticeFile := android.PathForModuleOut(ctx, "NOTICE.html.gz") + android.BuildNoticeHtmlOutputFromLicenseMetadata(ctx, noticeFile) + noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz") + builder := android.NewRuleBuilder(pctx, ctx) + builder.Command().Text("cp"). + Input(noticeFile). + Output(noticeAssetPath) + builder.Build("notice_dir", "Building notice dir") + a.aapt.noticeFile = android.OptionalPathForPath(noticeAssetPath) } a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) @@ -681,7 +638,21 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } certificates := processMainCert(a.ModuleBase, a.getCertString(ctx), certificateDeps, ctx) - a.certificate = certificates[0] + + // This can be reached with an empty certificate list if AllowMissingDependencies is set + // and the certificate property for this module is a module reference to a missing module. + if len(certificates) > 0 { + a.certificate = certificates[0] + } else { + if !ctx.Config().AllowMissingDependencies() && len(ctx.GetMissingDependencies()) > 0 { + panic("Should only get here if AllowMissingDependencies set and there are missing dependencies") + } + // Set a certificate to avoid panics later when accessing it. + a.certificate = Certificate{ + Key: android.PathForModuleOut(ctx, "missing.pk8"), + Pem: android.PathForModuleOut(ctx, "missing.pem"), + } + } // Build a final signed app package. packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk") @@ -1450,7 +1421,8 @@ func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *An } type bazelAndroidAppAttributes struct { - *javaLibraryAttributes + *javaCommonAttributes + Deps bazel.LabelListAttribute Manifest bazel.Label Custom_package *string Resource_files bazel.LabelListAttribute @@ -1460,7 +1432,16 @@ type bazelAndroidAppAttributes struct { // ConvertWithBp2build is used to convert android_app to Bazel. func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - libAttrs := a.convertLibraryAttrsBp2Build(ctx) + commonAttrs, depLabels := a.convertLibraryAttrsBp2Build(ctx) + + deps := depLabels.Deps + if !commonAttrs.Srcs.IsEmpty() { + deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them + } else if !deps.IsEmpty() || !depLabels.StaticDeps.IsEmpty() { + ctx.ModuleErrorf("android_app has dynamic or static dependencies but no sources." + + " Bazel does not allow direct dependencies without sources nor exported" + + " dependencies on android_binary rule.") + } manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") @@ -1483,7 +1464,8 @@ func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) { } attrs := &bazelAndroidAppAttributes{ - libAttrs, + commonAttrs, + deps, android.BazelLabelForModuleSrcSingle(ctx, manifest), // TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES a.overridableAppProperties.Package_name, diff --git a/java/app_import.go b/java/app_import.go index 3e5f972a4..b017eca60 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -22,6 +22,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/provenance" ) func init() { @@ -57,6 +58,8 @@ type AndroidAppImport struct { installPath android.InstallPath hideApexVariantFromMake bool + + provenanceMetaDataFile android.OutputPath } type AndroidAppImportProperties struct { @@ -343,6 +346,8 @@ 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) + a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath) } // TODO: androidmk converter jni libs @@ -368,6 +373,10 @@ func (a *AndroidAppImport) Certificate() Certificate { return a.certificate } +func (a *AndroidAppImport) ProvenanceMetaDataFile() android.OutputPath { + return a.provenanceMetaDataFile +} + var dpiVariantGroupType reflect.Type var archVariantGroupType reflect.Type var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"} @@ -457,7 +466,7 @@ func createVariantGroupType(variants []string, variantGroupName string) reflect. // apk: "prebuilts/example_xhdpi.apk", // }, // }, -// certificate: "PRESIGNED", +// presigned: true, // } func AndroidAppImportFactory() android.Module { module := &AndroidAppImport{} diff --git a/java/app_import_test.go b/java/app_import_test.go index efa52c178..8f6c75fa9 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -53,6 +53,11 @@ func TestAndroidAppImport(t *testing.T) { if expected != signingFlag { t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) } + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) } func TestAndroidAppImport_NoDexPreopt(t *testing.T) { @@ -74,6 +79,12 @@ func TestAndroidAppImport_NoDexPreopt(t *testing.T) { variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil { t.Errorf("dexpreopt shouldn't have run.") } + + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) } func TestAndroidAppImport_Presigned(t *testing.T) { @@ -102,6 +113,12 @@ func TestAndroidAppImport_Presigned(t *testing.T) { if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil { t.Errorf("can't find aligning rule") } + + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) } func TestAndroidAppImport_SigningLineage(t *testing.T) { @@ -137,6 +154,12 @@ func TestAndroidAppImport_SigningLineage(t *testing.T) { if expected != signingFlag { t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) } + + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) } func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) { @@ -163,6 +186,12 @@ func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) { if expected != signingFlag { t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) } + + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) } func TestAndroidAppImport_DefaultDevCert(t *testing.T) { @@ -192,6 +221,12 @@ func TestAndroidAppImport_DefaultDevCert(t *testing.T) { if expected != signingFlag { t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) } + + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) } func TestAndroidAppImport_DpiVariants(t *testing.T) { @@ -214,40 +249,46 @@ func TestAndroidAppImport_DpiVariants(t *testing.T) { } ` testCases := []struct { - name string - aaptPreferredConfig *string - aaptPrebuiltDPI []string - expected string + name string + aaptPreferredConfig *string + aaptPrebuiltDPI []string + expected string + expectedProvenanceMetaDataArtifactPath string }{ { - name: "no preferred", - aaptPreferredConfig: nil, - aaptPrebuiltDPI: []string{}, - expected: "verify_uses_libraries/apk/app.apk", + name: "no preferred", + aaptPreferredConfig: nil, + aaptPrebuiltDPI: []string{}, + expected: "verify_uses_libraries/apk/app.apk", + expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app.apk", }, { - name: "AAPTPreferredConfig matches", - aaptPreferredConfig: proptools.StringPtr("xhdpi"), - aaptPrebuiltDPI: []string{"xxhdpi", "ldpi"}, - expected: "verify_uses_libraries/apk/app_xhdpi.apk", + name: "AAPTPreferredConfig matches", + aaptPreferredConfig: proptools.StringPtr("xhdpi"), + aaptPrebuiltDPI: []string{"xxhdpi", "ldpi"}, + expected: "verify_uses_libraries/apk/app_xhdpi.apk", + expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xhdpi.apk", }, { - name: "AAPTPrebuiltDPI matches", - aaptPreferredConfig: proptools.StringPtr("mdpi"), - aaptPrebuiltDPI: []string{"xxhdpi", "xhdpi"}, - expected: "verify_uses_libraries/apk/app_xxhdpi.apk", + name: "AAPTPrebuiltDPI matches", + aaptPreferredConfig: proptools.StringPtr("mdpi"), + aaptPrebuiltDPI: []string{"xxhdpi", "xhdpi"}, + expected: "verify_uses_libraries/apk/app_xxhdpi.apk", + expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xxhdpi.apk", }, { - name: "non-first AAPTPrebuiltDPI matches", - aaptPreferredConfig: proptools.StringPtr("mdpi"), - aaptPrebuiltDPI: []string{"ldpi", "xhdpi"}, - expected: "verify_uses_libraries/apk/app_xhdpi.apk", + name: "non-first AAPTPrebuiltDPI matches", + aaptPreferredConfig: proptools.StringPtr("mdpi"), + aaptPrebuiltDPI: []string{"ldpi", "xhdpi"}, + expected: "verify_uses_libraries/apk/app_xhdpi.apk", + expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xhdpi.apk", }, { - name: "no matches", - aaptPreferredConfig: proptools.StringPtr("mdpi"), - aaptPrebuiltDPI: []string{"ldpi", "xxxhdpi"}, - expected: "verify_uses_libraries/apk/app.apk", + name: "no matches", + aaptPreferredConfig: proptools.StringPtr("mdpi"), + aaptPrebuiltDPI: []string{"ldpi", "xxxhdpi"}, + expected: "verify_uses_libraries/apk/app.apk", + expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app.apk", }, } @@ -270,6 +311,12 @@ func TestAndroidAppImport_DpiVariants(t *testing.T) { if strings.HasSuffix(matches[1], test.expected) { t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1]) } + + provenanceMetaDataRule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", test.expectedProvenanceMetaDataArtifactPath, provenanceMetaDataRule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", provenanceMetaDataRule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", provenanceMetaDataRule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", provenanceMetaDataRule.Args["install_path"]) } } @@ -290,16 +337,25 @@ func TestAndroidAppImport_Filename(t *testing.T) { `) testCases := []struct { - name string - expected string + name string + expected string + onDevice string + expectedArtifactPath string + expectedMetaDataPath string }{ { - name: "foo", - expected: "foo.apk", + name: "foo", + expected: "foo.apk", + onDevice: "/system/app/foo/foo.apk", + expectedArtifactPath: "prebuilts/apk/app.apk", + expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", }, { - name: "bar", - expected: "bar_sample.apk", + name: "bar", + expected: "bar_sample.apk", + onDevice: "/system/app/bar/bar_sample.apk", + expectedArtifactPath: "prebuilts/apk/app.apk", + expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/bar/provenance_metadata.textproto", }, } @@ -316,15 +372,23 @@ func TestAndroidAppImport_Filename(t *testing.T) { t.Errorf("Incorrect LOCAL_INSTALLED_MODULE_STEM value '%s', expected '%s'", actualValues, expectedValues) } + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", test.expectedArtifactPath, rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", test.expectedMetaDataPath, rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", test.name, rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", test.onDevice, rule.Args["install_path"]) } } func TestAndroidAppImport_ArchVariants(t *testing.T) { // The test config's target arch is ARM64. testCases := []struct { - name string - bp string - expected string + name string + bp string + expected string + artifactPath string + metaDataPath string + installPath string }{ { name: "matching arch", @@ -343,7 +407,9 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { }, } `, - expected: "verify_uses_libraries/apk/app_arm64.apk", + expected: "verify_uses_libraries/apk/app_arm64.apk", + artifactPath: "prebuilts/apk/app_arm64.apk", + installPath: "/system/app/foo/foo.apk", }, { name: "no matching arch", @@ -362,7 +428,9 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { }, } `, - expected: "verify_uses_libraries/apk/app.apk", + expected: "verify_uses_libraries/apk/app.apk", + artifactPath: "prebuilts/apk/app.apk", + installPath: "/system/app/foo/foo.apk", }, { name: "no matching arch without default", @@ -380,7 +448,9 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { }, } `, - expected: "", + expected: "", + artifactPath: "prebuilts/apk/app_arm.apk", + installPath: "/system/app/foo/foo.apk", }, } @@ -393,6 +463,8 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { if variant.Module().Enabled() { t.Error("module should have been disabled, but wasn't") } + rule := variant.MaybeRule("genProvenanceMetaData") + android.AssertDeepEquals(t, "Provenance metadata is not empty", android.TestingBuildParams{}, rule) continue } jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command @@ -403,6 +475,11 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { if strings.HasSuffix(matches[1], test.expected) { t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1]) } + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", test.artifactPath, rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", test.installPath, rule.Args["install_path"]) } } diff --git a/java/app_test.go b/java/app_test.go index 16bbec158..6a4508cd6 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -27,7 +27,6 @@ import ( "android/soong/android" "android/soong/cc" "android/soong/dexpreopt" - "android/soong/genrule" ) // testApp runs tests using the prepareForJavaTest @@ -2722,116 +2721,6 @@ func TestCodelessApp(t *testing.T) { } } -func TestEmbedNotice(t *testing.T) { - result := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - cc.PrepareForTestWithCcDefaultModules, - genrule.PrepareForTestWithGenRuleBuildComponents, - android.MockFS{ - "APP_NOTICE": nil, - "GENRULE_NOTICE": nil, - "LIB_NOTICE": nil, - "TOOL_NOTICE": nil, - }.AddToFixture(), - ).RunTestWithBp(t, ` - android_app { - name: "foo", - srcs: ["a.java"], - static_libs: ["javalib"], - jni_libs: ["libjni"], - notice: "APP_NOTICE", - embed_notices: true, - sdk_version: "current", - } - - // No embed_notice flag - android_app { - name: "bar", - srcs: ["a.java"], - jni_libs: ["libjni"], - notice: "APP_NOTICE", - sdk_version: "current", - } - - // No NOTICE files - android_app { - name: "baz", - srcs: ["a.java"], - embed_notices: true, - sdk_version: "current", - } - - cc_library { - name: "libjni", - system_shared_libs: [], - stl: "none", - notice: "LIB_NOTICE", - sdk_version: "current", - } - - java_library { - name: "javalib", - srcs: [ - ":gen", - ], - sdk_version: "current", - } - - genrule { - name: "gen", - tools: ["gentool"], - out: ["gen.java"], - notice: "GENRULE_NOTICE", - } - - java_binary_host { - name: "gentool", - srcs: ["b.java"], - notice: "TOOL_NOTICE", - } - `) - - // foo has NOTICE files to process, and embed_notices is true. - foo := result.ModuleForTests("foo", "android_common") - // verify merge notices rule. - mergeNotices := foo.Rule("mergeNoticesRule") - noticeInputs := mergeNotices.Inputs.Strings() - // TOOL_NOTICE should be excluded as it's a host module. - if len(mergeNotices.Inputs) != 3 { - t.Errorf("number of input notice files: expected = 3, actual = %q", noticeInputs) - } - if !inList("APP_NOTICE", noticeInputs) { - t.Errorf("APP_NOTICE is missing from notice files, %q", noticeInputs) - } - if !inList("LIB_NOTICE", noticeInputs) { - t.Errorf("LIB_NOTICE is missing from notice files, %q", noticeInputs) - } - if !inList("GENRULE_NOTICE", noticeInputs) { - t.Errorf("GENRULE_NOTICE is missing from notice files, %q", noticeInputs) - } - // aapt2 flags should include -A <NOTICE dir> so that its contents are put in the APK's /assets. - res := foo.Output("package-res.apk") - aapt2Flags := res.Args["flags"] - e := "-A out/soong/.intermediates/foo/android_common/NOTICE" - android.AssertStringDoesContain(t, "expected.apkPath", aapt2Flags, e) - - // bar has NOTICE files to process, but embed_notices is not set. - bar := result.ModuleForTests("bar", "android_common") - res = bar.Output("package-res.apk") - aapt2Flags = res.Args["flags"] - e = "-A out/soong/.intermediates/bar/android_common/NOTICE" - android.AssertStringDoesNotContain(t, "bar shouldn't have the asset dir flag for NOTICE", aapt2Flags, e) - - // baz's embed_notice is true, but it doesn't have any NOTICE files. - baz := result.ModuleForTests("baz", "android_common") - res = baz.Output("package-res.apk") - aapt2Flags = res.Args["flags"] - e = "-A out/soong/.intermediates/baz/android_common/NOTICE" - if strings.Contains(aapt2Flags, e) { - t.Errorf("baz shouldn't have the asset dir flag for NOTICE: %q", e) - } -} - func TestUncompressDex(t *testing.T) { testCases := []struct { name string @@ -3059,3 +2948,24 @@ func TestTargetSdkVersionManifestFixer(t *testing.T) { android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) } } + +func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + ).RunTestWithBp(t, ` + android_app { + name: "foo", + srcs: ["a.java"], + certificate: ":missing_certificate", + sdk_version: "current", + }`) + + foo := result.ModuleForTests("foo", "android_common") + fooApk := foo.Output("foo.apk") + if fooApk.Rule != android.ErrorRule { + t.Fatalf("expected ErrorRule for foo.apk, got %s", fooApk.Rule.String()) + } + android.AssertStringDoesContain(t, "expected error rule message", fooApk.Args["error"], "missing dependencies: missing_certificate\n") +} diff --git a/java/base.go b/java/base.go index 9978a66fc..b925350a0 100644 --- a/java/base.go +++ b/java/base.go @@ -185,12 +185,12 @@ type CommonProperties struct { // constructing a new module. type DeviceProperties struct { // If not blank, set to the version of the sdk to compile against. - // Defaults to compiling against the current platform. + // Defaults to private. // Values are of one of the following forms: - // 1) numerical API level or "current" - // 2) An SDK kind with an API level: "<sdk kind>_<API level>". See - // build/soong/android/sdk_version.go for the complete and up to date list of - // SDK kinds. If the SDK kind value is empty, it will be set to public. + // 1) numerical API level, "current", "none", or "core_platform" + // 2) An SDK kind with an API level: "<sdk kind>_<API level>" + // See build/soong/android/sdk_version.go for the complete and up to date list of SDK kinds. + // If the SDK kind is empty, it will be set to public. Sdk_version *string // if not blank, set the minimum version of the sdk that the compiled artifacts will run against. @@ -207,7 +207,7 @@ type DeviceProperties struct { // Whether to compile against the platform APIs instead of an SDK. // If true, then sdk_version must be empty. The value of this field - // is ignored when module's type isn't android_app. + // is ignored when module's type isn't android_app, android_test, or android_test_helper_app. Platform_apis *bool Aidl struct { @@ -872,6 +872,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB // classpath flags.bootClasspath = append(flags.bootClasspath, deps.bootClasspath...) flags.classpath = append(flags.classpath, deps.classpath...) + flags.dexClasspath = append(flags.dexClasspath, deps.dexClasspath...) flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...) flags.processorPath = append(flags.processorPath, deps.processorPath...) flags.errorProneProcessorPath = append(flags.errorProneProcessorPath, deps.errorProneProcessorPath...) @@ -1047,12 +1048,24 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } } + // We don't currently run annotation processors in turbine, which means we can't use turbine + // generated header jars when an annotation processor that generates API is enabled. One + // exception (handled further below) is when kotlin sources are enabled, in which case turbine + // is used to run all of the annotation processors. + disableTurbine := deps.disableTurbine + // Collect .java files for AIDEGen j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...) var kotlinJars android.Paths + var kotlinHeaderJars android.Paths if srcFiles.HasExt(".kt") { + // When using kotlin sources turbine is used to generate annotation processor sources, + // including for annotation processors that generate API, so we can use turbine for + // java sources too. + disableTurbine = false + // user defined kotlin flags. kotlincFlags := j.properties.Kotlincflags CheckKotlincFlags(ctx, kotlincFlags) @@ -1090,6 +1103,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { flags.classpath = append(flags.classpath, deps.kotlinStdlib...) flags.classpath = append(flags.classpath, deps.kotlinAnnotations...) + flags.dexClasspath = append(flags.dexClasspath, deps.kotlinAnnotations...) + flags.kotlincClasspath = append(flags.kotlincClasspath, flags.bootClasspath...) flags.kotlincClasspath = append(flags.kotlincClasspath, flags.classpath...) @@ -1106,18 +1121,24 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) - kotlinCompile(ctx, kotlinJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags) + kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) + kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags) if ctx.Failed() { return } // Make javac rule depend on the kotlinc rule - flags.classpath = append(flags.classpath, kotlinJar) + flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...) kotlinJars = append(kotlinJars, kotlinJar) + kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar) + // Jar kotlin classes into the final jar after javac if BoolDefault(j.properties.Static_kotlin_stdlib, true) { kotlinJars = append(kotlinJars, deps.kotlinStdlib...) + kotlinHeaderJars = append(kotlinHeaderJars, deps.kotlinStdlib...) + } else { + flags.dexClasspath = append(flags.dexClasspath, deps.kotlinStdlib...) } } @@ -1129,7 +1150,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { enableSharding := false var headerJarFileWithoutDepsOrJarjar android.Path - if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine { + if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine { if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 { enableSharding = true // Formerly, there was a check here that prevented annotation processors @@ -1139,7 +1160,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { // with sharding enabled. See: b/77284273. } headerJarFileWithoutDepsOrJarjar, j.headerJarFile = - j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars) + j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinHeaderJars) if ctx.Failed() { return } @@ -1673,6 +1694,8 @@ func (j *Module) IDEInfo(dpInfo *android.IdeInfo) { dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String()) } dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...) + dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...) + dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...) } func (j *Module) CompilerDeps() []string { @@ -1842,6 +1865,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } else if sdkDep.useFiles { // sdkDep.jar is actually equivalent to turbine header.jar. deps.classpath = append(deps.classpath, sdkDep.jars...) + deps.dexClasspath = append(deps.dexClasspath, sdkDep.jars...) deps.aidlPreprocess = sdkDep.aidl } else { deps.aidlPreprocess = sdkDep.aidl @@ -1866,7 +1890,9 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: - deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) + depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx)) + deps.classpath = append(deps.classpath, depHeaderJars...) + deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -1885,6 +1911,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...) case libTag, instrumentationForTag: deps.classpath = append(deps.classpath, dep.HeaderJars...) + deps.dexClasspath = append(deps.dexClasspath, dep.HeaderJars...) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...) deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine @@ -1952,6 +1979,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag: checkProducesJars(ctx, dep) deps.classpath = append(deps.classpath, dep.Srcs()...) + deps.dexClasspath = append(deps.classpath, dep.Srcs()...) case staticLibTag: checkProducesJars(ctx, dep) deps.classpath = append(deps.classpath, dep.Srcs()...) diff --git a/java/builder.go b/java/builder.go index e64a61f5c..c0fadd42c 100644 --- a/java/builder.go +++ b/java/builder.go @@ -131,31 +131,28 @@ var ( turbine, turbineRE = pctx.RemoteStaticRules("turbine", blueprint.RuleParams{ - Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + - `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} --output $out.tmp ` + - `--temp_dir "$outDir" --sources @$out.rsp --source_jars $srcJars ` + + Command: `$reTemplate${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.TurbineJar} $outputFlags ` + + `--sources @$out.rsp --source_jars $srcJars ` + `--javacopts ${config.CommonJdkFlags} ` + - `$javacFlags -source $javaVersion -target $javaVersion -- $bootClasspath $classpath && ` + - `${config.Ziptime} $out.tmp && ` + - `(if cmp -s $out.tmp $out ; then rm $out.tmp ; else mv $out.tmp $out ; fi )`, + `$javacFlags -source $javaVersion -target $javaVersion -- $turbineFlags && ` + + `(for o in $outputs; do if cmp -s $${o}.tmp $${o} ; then rm $${o}.tmp ; else mv $${o}.tmp $${o} ; fi; done )`, CommandDeps: []string{ "${config.TurbineJar}", "${config.JavaCmd}", - "${config.Ziptime}", }, Rspfile: "$out.rsp", RspfileContent: "$in", Restat: true, }, &remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"}, - ExecStrategy: "${config.RETurbineExecStrategy}", - Inputs: []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"}, - RSPFiles: []string{"${out}.rsp"}, - OutputFiles: []string{"$out.tmp"}, - OutputDirectories: []string{"$outDir"}, - ToolchainInputs: []string{"${config.JavaCmd}"}, - Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, - }, []string{"javacFlags", "bootClasspath", "classpath", "srcJars", "outDir", "javaVersion"}, []string{"implicits"}) + ExecStrategy: "${config.RETurbineExecStrategy}", + Inputs: []string{"${config.TurbineJar}", "${out}.rsp", "$implicits"}, + RSPFiles: []string{"${out}.rsp"}, + OutputFiles: []string{"$rbeOutputs"}, + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + []string{"javacFlags", "turbineFlags", "outputFlags", "javaVersion", "outputs", "rbeOutputs", "srcJars"}, []string{"implicits"}) jar, jarRE = pctx.RemoteStaticRules("jar", blueprint.RuleParams{ @@ -247,16 +244,33 @@ func init() { } type javaBuilderFlags struct { - javacFlags string - bootClasspath classpath - classpath classpath + javacFlags string + + // bootClasspath is the list of jars that form the boot classpath (generally the java.* and + // android.* classes) for tools that still use it. javac targeting 1.9 or higher uses + // systemModules and java9Classpath instead. + bootClasspath classpath + + // classpath is the list of jars that form the classpath for javac and kotlinc rules. It + // contains header jars for all static and non-static dependencies. + classpath classpath + + // dexClasspath is the list of jars that form the classpath for d8 and r8 rules. It contains + // header jars for all non-static dependencies. Static dependencies have already been + // combined into the program jar. + dexClasspath classpath + + // java9Classpath is the list of jars that will be added to the classpath when targeting + // 1.9 or higher. It generally contains the android.* classes, while the java.* classes + // are provided by systemModules. java9Classpath classpath - processorPath classpath - processors []string - systemModules *systemModules - aidlFlags string - aidlDeps android.Paths - javaVersion javaVersion + + processorPath classpath + processors []string + systemModules *systemModules + aidlFlags string + aidlDeps android.Paths + javaVersion javaVersion errorProneExtraJavacFlags string errorProneProcessorPath classpath @@ -341,11 +355,8 @@ func emitXrefRule(ctx android.ModuleContext, xrefFile android.WritablePath, idx }) } -func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath, - srcFiles, srcJars android.Paths, flags javaBuilderFlags) { - +func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags) (string, android.Paths) { var deps android.Paths - deps = append(deps, srcJars...) classpath := flags.classpath @@ -367,20 +378,31 @@ func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android. } deps = append(deps, classpath...) - deps = append(deps, flags.processorPath...) + turbineFlags := bootClasspath + " " + classpath.FormTurbineClassPath("--classpath ") + + return turbineFlags, deps +} + +func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath, + srcFiles, srcJars android.Paths, flags javaBuilderFlags) { + + turbineFlags, deps := turbineFlags(ctx, flags) + + deps = append(deps, srcJars...) rule := turbine args := map[string]string{ - "javacFlags": flags.javacFlags, - "bootClasspath": bootClasspath, - "srcJars": strings.Join(srcJars.Strings(), " "), - "classpath": classpath.FormTurbineClassPath("--classpath "), - "outDir": android.PathForModuleOut(ctx, "turbine", "classes").String(), - "javaVersion": flags.javaVersion.String(), + "javacFlags": flags.javacFlags, + "srcJars": strings.Join(srcJars.Strings(), " "), + "javaVersion": flags.javaVersion.String(), + "turbineFlags": turbineFlags, + "outputFlags": "--output " + outputFile.String() + ".tmp", + "outputs": outputFile.String(), } if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") { rule = turbineRE args["implicits"] = strings.Join(deps.Strings(), ",") + args["rbeOutputs"] = outputFile.String() + ".tmp" } ctx.Build(pctx, android.BuildParams{ Rule: rule, @@ -392,6 +414,47 @@ func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android. }) } +// TurbineApt produces a rule to run annotation processors using turbine. +func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.WritablePath, + srcFiles, srcJars android.Paths, flags javaBuilderFlags) { + + turbineFlags, deps := turbineFlags(ctx, flags) + + deps = append(deps, srcJars...) + + deps = append(deps, flags.processorPath...) + turbineFlags += " " + flags.processorPath.FormTurbineClassPath("--processorpath ") + turbineFlags += " --processors " + strings.Join(flags.processors, " ") + + outputs := android.WritablePaths{outputSrcJar, outputResJar} + outputFlags := "--gensrc_output " + outputSrcJar.String() + ".tmp " + + "--resource_output " + outputResJar.String() + ".tmp" + + rule := turbine + args := map[string]string{ + "javacFlags": flags.javacFlags, + "srcJars": strings.Join(srcJars.Strings(), " "), + "javaVersion": flags.javaVersion.String(), + "turbineFlags": turbineFlags, + "outputFlags": outputFlags, + "outputs": strings.Join(outputs.Strings(), " "), + } + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") { + rule = turbineRE + args["implicits"] = strings.Join(deps.Strings(), ",") + args["rbeOutputs"] = outputSrcJar.String() + ".tmp," + outputResJar.String() + ".tmp" + } + ctx.Build(pctx, android.BuildParams{ + Rule: rule, + Description: "turbine apt", + Output: outputs[0], + ImplicitOutputs: outputs[1:], + Inputs: srcFiles, + Implicits: deps, + Args: args, + }) +} + // 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. @@ -653,6 +716,6 @@ func (x *systemModules) FormTurbineSystemModulesPath(forceEmpty bool) (string, a } else if forceEmpty { return `--bootclasspath ""`, nil } else { - return "", nil + return "--system ${config.JavaHome}", nil } } diff --git a/java/config/config.go b/java/config/config.go index 05dfde635..95b841fa7 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -26,7 +26,8 @@ import ( ) var ( - pctx = android.NewPackageContext("android/soong/java/config") + pctx = android.NewPackageContext("android/soong/java/config") + exportedVars = android.NewExportedVariables(pctx) LegacyCorePlatformBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"} LegacyCorePlatformSystemModules = "legacy-core-platform-api-stubs-system-modules" @@ -50,33 +51,43 @@ var ( "core-icu4j", "core-oj", "core-libart", - // TODO: Could this be all updatable bootclasspath jars? - "updatable-media", - "framework-mediaprovider", - "framework-sdkextensions", - "android.net.ipsec.ike", } ) -const ( - JavaVmFlags = `-XX:OnError="cat hs_err_pid%p.log" -XX:CICompilerCount=6 -XX:+UseDynamicNumberOfGCThreads` - JavacVmFlags = `-J-XX:OnError="cat hs_err_pid%p.log" -J-XX:CICompilerCount=6 -J-XX:+UseDynamicNumberOfGCThreads -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1` +var ( + JavacVmFlags = strings.Join(javacVmFlagsList, " ") + javaVmFlagsList = []string{ + `-XX:OnError="cat hs_err_pid%p.log"`, + "-XX:CICompilerCount=6", + "-XX:+UseDynamicNumberOfGCThreads", + } + javacVmFlagsList = []string{ + `-J-XX:OnError="cat hs_err_pid%p.log"`, + "-J-XX:CICompilerCount=6", + "-J-XX:+UseDynamicNumberOfGCThreads", + "-J-XX:+TieredCompilation", + "-J-XX:TieredStopAtLevel=1", + } ) func init() { pctx.Import("github.com/google/blueprint/bootstrap") - pctx.StaticVariable("JavacHeapSize", "2048M") - pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}") + exportedVars.ExportStringStaticVariable("JavacHeapSize", "2048M") + exportedVars.ExportStringStaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}") // ErrorProne can use significantly more memory than javac alone, give it a higher heap // size (b/221480398). - pctx.StaticVariable("ErrorProneHeapSize", "4096M") - pctx.StaticVariable("ErrorProneHeapFlags", "-J-Xmx${ErrorProneHeapSize}") + exportedVars.ExportStringStaticVariable("ErrorProneHeapSize", "4096M") + exportedVars.ExportStringStaticVariable("ErrorProneHeapFlags", "-J-Xmx${ErrorProneHeapSize}") - pctx.StaticVariable("DexFlags", "-JXX:OnError='cat hs_err_pid%p.log' -JXX:CICompilerCount=6 -JXX:+UseDynamicNumberOfGCThreads") + exportedVars.ExportStringListStaticVariable("DexFlags", []string{ + `-JXX:OnError="cat hs_err_pid%p.log"`, + "-JXX:CICompilerCount=6", + "-JXX:+UseDynamicNumberOfGCThreads", + }) - pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{ + exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{ `-Xmaxerrs 9999999`, `-encoding UTF-8`, `-sourcepath ""`, @@ -90,10 +101,10 @@ func init() { // b/65004097: prevent using java.lang.invoke.StringConcatFactory when using -target 1.9 `-XDstringConcat=inline`, - }, " ")) + }) - pctx.StaticVariable("JavaVmFlags", JavaVmFlags) - pctx.StaticVariable("JavacVmFlags", JavacVmFlags) + exportedVars.ExportStringListStaticVariable("JavaVmFlags", javaVmFlagsList) + exportedVars.ExportStringListStaticVariable("JavacVmFlags", javacVmFlagsList) pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS) @@ -189,6 +200,10 @@ func init() { hostJNIToolVariableWithSdkToolsPrebuilt("SignapkJniLibrary", "libconscrypt_openjdk_jni") } +func BazelJavaToolchainVars(config android.Config) string { + return android.BazelToolchainVars(config, exportedVars) +} + func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { if ctx.Config().AlwaysUsePrebuiltSdks() { diff --git a/java/config/error_prone.go b/java/config/error_prone.go index 48681b5c9..5f853c812 100644 --- a/java/config/error_prone.go +++ b/java/config/error_prone.go @@ -16,8 +16,6 @@ package config import ( "strings" - - "android/soong/android" ) var ( @@ -31,23 +29,23 @@ var ( ) // Wrapper that grabs value of val late so it can be initialized by a later module's init function -func errorProneVar(name string, val *[]string, sep string) { - pctx.VariableFunc(name, func(android.PackageVarContext) string { +func errorProneVar(val *[]string, sep string) func() string { + return func() string { return strings.Join(*val, sep) - }) + } } func init() { - errorProneVar("ErrorProneClasspath", &ErrorProneClasspath, ":") - errorProneVar("ErrorProneChecksError", &ErrorProneChecksError, " ") - errorProneVar("ErrorProneChecksWarning", &ErrorProneChecksWarning, " ") - errorProneVar("ErrorProneChecksDefaultDisabled", &ErrorProneChecksDefaultDisabled, " ") - errorProneVar("ErrorProneChecksOff", &ErrorProneChecksOff, " ") - errorProneVar("ErrorProneFlags", &ErrorProneFlags, " ") - pctx.StaticVariable("ErrorProneChecks", strings.Join([]string{ + exportedVars.ExportVariableFuncVariable("ErrorProneClasspath", errorProneVar(&ErrorProneClasspath, ":")) + exportedVars.ExportVariableFuncVariable("ErrorProneChecksError", errorProneVar(&ErrorProneChecksError, " ")) + exportedVars.ExportVariableFuncVariable("ErrorProneChecksWarning", errorProneVar(&ErrorProneChecksWarning, " ")) + exportedVars.ExportVariableFuncVariable("ErrorProneChecksDefaultDisabled", errorProneVar(&ErrorProneChecksDefaultDisabled, " ")) + exportedVars.ExportVariableFuncVariable("ErrorProneChecksOff", errorProneVar(&ErrorProneChecksOff, " ")) + exportedVars.ExportVariableFuncVariable("ErrorProneFlags", errorProneVar(&ErrorProneFlags, " ")) + exportedVars.ExportStringListStaticVariable("ErrorProneChecks", []string{ "${ErrorProneChecksOff}", "${ErrorProneChecksError}", "${ErrorProneChecksWarning}", "${ErrorProneChecksDefaultDisabled}", - }, " ")) + }) } diff --git a/java/config/kotlin.go b/java/config/kotlin.go index 6cb61f306..fc63f4dfb 100644 --- a/java/config/kotlin.go +++ b/java/config/kotlin.go @@ -34,6 +34,7 @@ func init() { pctx.SourcePathVariable("KotlinKaptJar", "external/kotlinc/lib/kotlin-annotation-processing.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") // These flags silence "Illegal reflective access" warnings when running kapt in OpenJDK9+ pctx.StaticVariable("KaptSuppressJDK9Warnings", strings.Join([]string{ @@ -47,4 +48,9 @@ func init() { pctx.StaticVariable("KotlincSuppressJDK9Warnings", strings.Join([]string{ "-J--add-opens=java.base/java.util=ALL-UNNAMED", // https://youtrack.jetbrains.com/issue/KT-43704 }, " ")) + + pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{ + // b/222162908: prevent kotlinc from reading /tmp/build.txt + "-Didea.plugins.compatible.build=999.SNAPSHOT", + }, " ")) } diff --git a/java/dex.go b/java/dex.go index 474694a51..84665e7b5 100644 --- a/java/dex.go +++ b/java/dex.go @@ -132,12 +132,15 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", `--no-data-resources ` + `-printmapping ${outDict} ` + `-printusage ${outUsage} ` + + `--deps-file ${out}.d ` + `$r8Flags && ` + `touch "${outDict}" "${outUsage}" && ` + `${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`, + Depfile: "${out}.d", + Deps: blueprint.DepsGCC, CommandDeps: []string{ "${config.R8Cmd}", "${config.Zip2ZipCmd}", @@ -205,10 +208,10 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, func d8Flags(flags javaBuilderFlags) (d8Flags []string, d8Deps android.Paths) { d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...) - d8Flags = append(d8Flags, flags.classpath.FormRepeatedClassPath("--lib ")...) + d8Flags = append(d8Flags, flags.dexClasspath.FormRepeatedClassPath("--lib ")...) d8Deps = append(d8Deps, flags.bootClasspath...) - d8Deps = append(d8Deps, flags.classpath...) + d8Deps = append(d8Deps, flags.dexClasspath...) return d8Flags, d8Deps } @@ -231,11 +234,11 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars")) - r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars")) + r8Flags = append(r8Flags, flags.dexClasspath.FormJavaClassPath("-libraryjars")) r8Deps = append(r8Deps, proguardRaiseDeps...) r8Deps = append(r8Deps, flags.bootClasspath...) - r8Deps = append(r8Deps, flags.classpath...) + r8Deps = append(r8Deps, flags.dexClasspath...) flagFiles := android.Paths{ android.PathForSource(ctx, "build/make/core/proguard.flags"), diff --git a/java/dex_test.go b/java/dex_test.go new file mode 100644 index 000000000..fbdccb65d --- /dev/null +++ b/java/dex_test.go @@ -0,0 +1,103 @@ +// Copyright 2022 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 ( + "testing" + + "android/soong/android" +) + +func TestR8(t *testing.T) { + result := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd.RunTestWithBp(t, ` + android_app { + name: "app", + srcs: ["foo.java"], + libs: ["lib"], + static_libs: ["static_lib"], + platform_apis: true, + } + + java_library { + name: "lib", + srcs: ["foo.java"], + } + + java_library { + name: "static_lib", + srcs: ["foo.java"], + } + `) + + app := result.ModuleForTests("app", "android_common") + lib := result.ModuleForTests("lib", "android_common") + staticLib := result.ModuleForTests("static_lib", "android_common") + + appJavac := app.Rule("javac") + appR8 := app.Rule("r8") + libHeader := lib.Output("turbine-combined/lib.jar").Output + staticLibHeader := staticLib.Output("turbine-combined/static_lib.jar").Output + + android.AssertStringDoesContain(t, "expected lib header jar in app javac classpath", + appJavac.Args["classpath"], libHeader.String()) + android.AssertStringDoesContain(t, "expected static_lib header jar in app javac classpath", + appJavac.Args["classpath"], staticLibHeader.String()) + + android.AssertStringDoesContain(t, "expected lib header jar in app r8 classpath", + appR8.Args["r8Flags"], libHeader.String()) + android.AssertStringDoesNotContain(t, "expected no static_lib header jar in app javac classpath", + appR8.Args["r8Flags"], staticLibHeader.String()) +} + +func TestD8(t *testing.T) { + result := PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd.RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: ["foo.java"], + libs: ["lib"], + static_libs: ["static_lib"], + installable: true, + } + + java_library { + name: "lib", + srcs: ["foo.java"], + } + + java_library { + name: "static_lib", + srcs: ["foo.java"], + } + `) + + foo := result.ModuleForTests("foo", "android_common") + lib := result.ModuleForTests("lib", "android_common") + staticLib := result.ModuleForTests("static_lib", "android_common") + + fooJavac := foo.Rule("javac") + fooD8 := foo.Rule("d8") + libHeader := lib.Output("turbine-combined/lib.jar").Output + staticLibHeader := staticLib.Output("turbine-combined/static_lib.jar").Output + + android.AssertStringDoesContain(t, "expected lib header jar in foo javac classpath", + fooJavac.Args["classpath"], libHeader.String()) + android.AssertStringDoesContain(t, "expected static_lib header jar in foo javac classpath", + fooJavac.Args["classpath"], staticLibHeader.String()) + + android.AssertStringDoesContain(t, "expected lib header jar in foo d8 classpath", + fooD8.Args["d8Flags"], libHeader.String()) + android.AssertStringDoesNotContain(t, "expected no static_lib header jar in foo javac classpath", + fooD8.Args["d8Flags"], staticLibHeader.String()) +} diff --git a/java/droidstubs.go b/java/droidstubs.go index 2921c3e82..3b1f7c041 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -433,6 +433,10 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a } } +func metalavaUseRbe(ctx android.ModuleContext) bool { + return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") +} + func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths, srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand { rule.Command().Text("rm -rf").Flag(homeDir.String()) @@ -441,7 +445,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi cmd := rule.Command() cmd.FlagWithArg("ANDROID_PREFS_ROOT=", homeDir.String()) - if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") { + if metalavaUseRbe(ctx) { rule.Remoteable(android.RemoteRuleSupports{RBE: true}) execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy) labels := map[string]string{"type": "tool", "name": "metalava"} @@ -477,7 +481,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi Flag("--format=v2"). FlagWithArg("--repeat-errors-max ", "10"). FlagWithArg("--hide ", "UnresolvedImport"). - FlagWithArg("--hide ", "InvalidNullability"). + FlagWithArg("--hide ", "InvalidNullabilityOverride"). // b/223382732 FlagWithArg("--hide ", "ChangedDefault") @@ -665,7 +669,9 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { } // TODO(b/183630617): rewrapper doesn't support restat rules - // rule.Restat() + if !metalavaUseRbe(ctx) { + rule.Restat() + } zipSyncCleanupCmd(rule, srcJarDir) diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 95ded34bb..534a8145f 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -295,6 +295,12 @@ func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android. return dexJar.Path() } +// HIDDENAPI_STUB_FLAGS_IMPL_FLAGS is the set of flags that identify implementation only signatures, +// i.e. those signatures that are not part of any API (including the hidden API). +var HIDDENAPI_STUB_FLAGS_IMPL_FLAGS = []string{} + +var HIDDENAPI_FLAGS_CSV_IMPL_FLAGS = []string{"blocked"} + // buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file. // // The rule is initialized but not built so that the caller can modify it and select an appropriate @@ -345,7 +351,8 @@ func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, // If there are stub flag files that have been generated by fragments on which this depends then // use them to validate the stub flag file generated by the rules created by this method. if len(stubFlagSubsets) > 0 { - validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets) + validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets, + HIDDENAPI_STUB_FLAGS_IMPL_FLAGS) // Add the file that indicates that the file generated by this is valid. // @@ -904,7 +911,8 @@ func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc st // If there are flag files that have been generated by fragments on which this depends then use // them to validate the flag file generated by the rules created by this method. if len(flagSubsets) > 0 { - validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets) + validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets, + HIDDENAPI_FLAGS_CSV_IMPL_FLAGS) // Add the file that indicates that the file generated by this is valid. // @@ -968,13 +976,29 @@ func buildRuleSignaturePatternsFile( return patternsFile } -// buildRuleRemoveBlockedFlag creates a rule that will remove entries from the input path which -// only have blocked flags. It will not remove entries that have blocked as well as other flags, -// e.g. blocked,core-platform-api. -func buildRuleRemoveBlockedFlag(ctx android.BuilderContext, name string, desc string, inputPath android.Path, filteredPath android.WritablePath) { +// buildRuleRemoveSignaturesWithImplementationFlags creates a rule that will remove signatures from +// the input flags file which have only the implementation flags, i.e. are not part of an API. +// +// The implementationFlags specifies the set of default flags that identifies the signature of a +// private, implementation only, member. Signatures that match those flags are removed from the +// flags as they are implementation only. +// +// This is used to remove implementation only signatures from the signature files that are persisted +// in the sdk snapshot as the sdk snapshots should not include implementation details. The +// signatures generated by this method will be compared by the buildRuleValidateOverlappingCsvFiles +// method which treats any missing signatures as if they were implementation only signatures. +func buildRuleRemoveSignaturesWithImplementationFlags(ctx android.BuilderContext, + name string, desc string, inputPath android.Path, filteredPath android.WritablePath, + implementationFlags []string) { + rule := android.NewRuleBuilder(pctx, ctx) + implementationFlagPattern := "" + for _, implementationFlag := range implementationFlags { + implementationFlagPattern = implementationFlagPattern + "," + implementationFlag + } rule.Command(). - Text(`grep -vE "^[^,]+,blocked$"`).Input(inputPath).Text(">").Output(filteredPath). + Text(`grep -vE "^[^,]+` + implementationFlagPattern + `$"`).Input(inputPath). + Text(">").Output(filteredPath). // Grep's exit code depends on whether it finds anything. It is 0 (build success) when it finds // something and 1 (build failure) when it does not and 2 (when it encounters an error). // However, while it is unlikely it is not an error if this does not find any matches. The @@ -986,7 +1010,14 @@ func buildRuleRemoveBlockedFlag(ctx android.BuilderContext, name string, desc st // buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated // by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file. -func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, csvSubsets SignatureCsvSubsets) android.WritablePath { +// +// The implementationFlags specifies the set of default flags that identifies the signature of a +// private, implementation only, member. A signature which is present in a monolithic flags subset +// defined by SignatureCsvSubset but which is not present in the flags file from the corresponding +// module is assumed to be an implementation only member and so must have these flags. +func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, + monolithicFilePath android.WritablePath, csvSubsets SignatureCsvSubsets, + implementationFlags []string) android.WritablePath { // The file which is used to record that the flags file is valid. validFile := pathForValidation(ctx, monolithicFilePath) @@ -994,14 +1025,19 @@ func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name strin rule := android.NewRuleBuilder(pctx, ctx) command := rule.Command(). BuiltTool("verify_overlaps"). - Input(monolithicFilePath) + FlagWithInput("--monolithic-flags ", monolithicFilePath) for _, subset := range csvSubsets { command. + Flag("--module-flags "). Textf("%s:%s", subset.CsvFile, subset.SignaturePatternsFile). Implicit(subset.CsvFile).Implicit(subset.SignaturePatternsFile) } + for _, implementationFlag := range implementationFlags { + command.FlagWithArg("--implementation-flag ", implementationFlag) + } + // If validation passes then update the file that records that. command.Text("&& touch").Output(validFile) rule.Build(name+"Validation", desc+" validation") @@ -1075,12 +1111,16 @@ func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents // Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be // compared against the monolithic stub flags. filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv") - buildRuleRemoveBlockedFlag(ctx, "modularHiddenApiFilteredStubFlags", "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV) + buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags", + "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV, + HIDDENAPI_STUB_FLAGS_IMPL_FLAGS) // Generate the filtered-flags.csv file which contains the filtered flags that will be compared // against the monolithic flags. filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv") - buildRuleRemoveBlockedFlag(ctx, "modularHiddenApiFilteredFlags", "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV) + buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags", + "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV, + HIDDENAPI_FLAGS_CSV_IMPL_FLAGS) // Store the paths in the info for use by other modules and sdk snapshot generation. output := HiddenAPIOutput{ diff --git a/java/java.go b/java/java.go index 895ce7af1..b34d6de8a 100644 --- a/java/java.go +++ b/java/java.go @@ -421,9 +421,25 @@ func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext android.SdkContext, } type deps struct { - classpath classpath - java9Classpath classpath - bootClasspath classpath + // bootClasspath is the list of jars that form the boot classpath (generally the java.* and + // android.* classes) for tools that still use it. javac targeting 1.9 or higher uses + // systemModules and java9Classpath instead. + bootClasspath classpath + + // classpath is the list of jars that form the classpath for javac and kotlinc rules. It + // contains header jars for all static and non-static dependencies. + classpath classpath + + // dexClasspath is the list of jars that form the classpath for d8 and r8 rules. It contains + // header jars for all non-static dependencies. Static dependencies have already been + // combined into the program jar. + dexClasspath classpath + + // java9Classpath is the list of jars that will be added to the classpath when targeting + // 1.9 or higher. It generally contains the android.* classes, while the java.* classes + // are provided by systemModules. + java9Classpath classpath + processorPath classpath errorProneProcessorPath classpath processorClasses []string @@ -1458,7 +1474,10 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) switch tag { - case libTag, staticLibTag: + case libTag: + flags.classpath = append(flags.classpath, dep.HeaderJars...) + flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...) + case staticLibTag: flags.classpath = append(flags.classpath, dep.HeaderJars...) case bootClasspathTag: flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...) @@ -1706,6 +1725,7 @@ func ImportFactoryHost() android.Module { android.InitPrebuiltModule(module, &module.properties.Jars) android.InitApexModule(module) + android.InitBazelModule(module) InitJavaModule(module, android.HostSupported) return module } @@ -2004,13 +2024,28 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, } } -type javaLibraryAttributes struct { +type javaCommonAttributes struct { Srcs bazel.LabelListAttribute - Deps bazel.LabelListAttribute + Plugins bazel.LabelListAttribute Javacopts bazel.StringListAttribute } -func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) *javaLibraryAttributes { +type javaDependencyLabels struct { + // Dependencies which DO NOT contribute to the API visible to upstream dependencies. + Deps bazel.LabelListAttribute + // Dependencies which DO contribute to the API visible to upstream dependencies. + StaticDeps bazel.LabelListAttribute +} + +// convertLibraryAttrsBp2Build converts a few shared attributes from java_* modules +// and also separates dependencies into dynamic dependencies and static dependencies. +// Each corresponding Bazel target type, can have a different method for handling +// dynamic vs. static dependencies, and so these are returned to the calling function. +type eventLogTagsAttributes struct { + Srcs bazel.LabelListAttribute +} + +func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *javaDependencyLabels) { var srcs bazel.LabelListAttribute archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{}) for axis, configToProps := range archVariantProps { @@ -2024,45 +2059,104 @@ func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) javaSrcPartition := "java" protoSrcPartition := "proto" + logtagSrcPartition := "logtag" srcPartitions := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{ - javaSrcPartition: bazel.LabelPartition{Extensions: []string{".java"}, Keep_remainder: true}, - protoSrcPartition: android.ProtoSrcLabelPartition, + javaSrcPartition: bazel.LabelPartition{Extensions: []string{".java"}, Keep_remainder: true}, + logtagSrcPartition: bazel.LabelPartition{Extensions: []string{".logtags", ".logtag"}}, + protoSrcPartition: android.ProtoSrcLabelPartition, }) - attrs := &javaLibraryAttributes{ - Srcs: srcPartitions[javaSrcPartition], + javaSrcs := srcPartitions[javaSrcPartition] + + var logtagsSrcs bazel.LabelList + if !srcPartitions[logtagSrcPartition].IsEmpty() { + logtagsLibName := m.Name() + "_logtags" + logtagsSrcs = bazel.MakeLabelList([]bazel.Label{{Label: ":" + logtagsLibName}}) + ctx.CreateBazelTargetModule( + bazel.BazelTargetModuleProperties{ + Rule_class: "event_log_tags", + Bzl_load_location: "//build/make/tools:event_log_tags.bzl", + }, + android.CommonAttributes{Name: logtagsLibName}, + &eventLogTagsAttributes{ + Srcs: srcPartitions[logtagSrcPartition], + }, + ) + } + javaSrcs.Append(bazel.MakeLabelListAttribute(logtagsSrcs)) + + var javacopts []string + if m.properties.Javacflags != nil { + javacopts = append(javacopts, m.properties.Javacflags...) + } + epEnabled := m.properties.Errorprone.Enabled + //TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable + if Bool(epEnabled) { + javacopts = append(javacopts, m.properties.Errorprone.Javacflags...) } - if m.properties.Javacflags != nil { - attrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags) + commonAttrs := &javaCommonAttributes{ + Srcs: javaSrcs, + Plugins: bazel.MakeLabelListAttribute( + android.BazelLabelForModuleDeps(ctx, m.properties.Plugins), + ), + Javacopts: bazel.MakeStringListAttribute(javacopts), } + depLabels := &javaDependencyLabels{} + var deps bazel.LabelList - sdkVersion := m.SdkVersion(ctx) - if sdkVersion.Kind == android.SdkPublic && sdkVersion.ApiLevel == android.FutureApiLevel { - // TODO(b/220869005) remove forced dependency on current public android.jar - deps.Add(&bazel.Label{Label: "//prebuilts/sdk:public_current_android_sdk_java_import"}) - } if m.properties.Libs != nil { deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Libs)) } + + var staticDeps bazel.LabelList if m.properties.Static_libs != nil { - //TODO(b/217236083) handle static libs similarly to Soong - deps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs)) + staticDeps.Append(android.BazelLabelForModuleDeps(ctx, m.properties.Static_libs)) } - protoDeps := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition]) - if protoDeps != nil { - deps.Add(protoDeps) - } + protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition]) + // Soong does not differentiate between a java_library and the Bazel equivalent of + // a java_proto_library + proto_library pair. Instead, in Soong proto sources are + // listed directly in the srcs of a java_library, and the classes produced + // by protoc are included directly in the resulting JAR. Thus upstream dependencies + // that depend on a java_library with proto sources can link directly to the protobuf API, + // and so this should be a static dependency. + staticDeps.Add(protoDepLabel) - attrs.Deps = bazel.MakeLabelListAttribute(deps) + depLabels.Deps = bazel.MakeLabelListAttribute(deps) + depLabels.StaticDeps = bazel.MakeLabelListAttribute(staticDeps) - return attrs + return commonAttrs, depLabels +} + +type javaLibraryAttributes struct { + *javaCommonAttributes + Deps bazel.LabelListAttribute + Exports bazel.LabelListAttribute } func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { - attrs := m.convertLibraryAttrsBp2Build(ctx) + commonAttrs, depLabels := m.convertLibraryAttrsBp2Build(ctx) + + deps := depLabels.Deps + if !commonAttrs.Srcs.IsEmpty() { + deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them + + sdkVersion := m.SdkVersion(ctx) + if sdkVersion.Kind == android.SdkPublic && sdkVersion.ApiLevel == android.FutureApiLevel { + // TODO(b/220869005) remove forced dependency on current public android.jar + deps.Add(bazel.MakeLabelAttribute("//prebuilts/sdk:public_current_android_sdk_java_import")) + } + } else if !depLabels.Deps.IsEmpty() { + ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.") + } + + attrs := &javaLibraryAttributes{ + javaCommonAttributes: commonAttrs, + Deps: deps, + Exports: depLabels.StaticDeps, + } props := bazel.BazelTargetModuleProperties{ Rule_class: "java_library", @@ -2073,15 +2167,30 @@ func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) { } type javaBinaryHostAttributes struct { - Srcs bazel.LabelListAttribute - Deps bazel.LabelListAttribute - Main_class string - Jvm_flags bazel.StringListAttribute - Javacopts bazel.StringListAttribute + *javaCommonAttributes + Deps bazel.LabelListAttribute + Runtime_deps bazel.LabelListAttribute + Main_class string + Jvm_flags bazel.StringListAttribute } // JavaBinaryHostBp2Build is for java_binary_host bp2build. func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { + commonAttrs, depLabels := m.convertLibraryAttrsBp2Build(ctx) + + deps := depLabels.Deps + deps.Append(depLabels.StaticDeps) + if m.binaryProperties.Jni_libs != nil { + deps.Append(bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs))) + } + + var runtimeDeps bazel.LabelListAttribute + if commonAttrs.Srcs.IsEmpty() { + // if there are no sources, then the dependencies can only be used at runtime + runtimeDeps = deps + deps = bazel.LabelListAttribute{} + } + mainClass := "" if m.binaryProperties.Main_class != nil { mainClass = *m.binaryProperties.Main_class @@ -2093,26 +2202,12 @@ func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) { } mainClass = mainClassInManifest } - srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)) - attrs := &javaBinaryHostAttributes{ - Srcs: srcs, - Main_class: mainClass, - } - if m.properties.Javacflags != nil { - attrs.Javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags) - } - - // Attribute deps - deps := []string{} - if m.properties.Static_libs != nil { - deps = append(deps, m.properties.Static_libs...) - } - if m.binaryProperties.Jni_libs != nil { - deps = append(deps, m.binaryProperties.Jni_libs...) - } - if len(deps) > 0 { - attrs.Deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, deps)) + attrs := &javaBinaryHostAttributes{ + javaCommonAttributes: commonAttrs, + Deps: deps, + Runtime_deps: runtimeDeps, + Main_class: mainClass, } // Attribute jvm_flags @@ -2155,8 +2250,16 @@ type bazelJavaImportAttributes struct { // java_import bp2Build converter. func (i *Import) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - //TODO(b/209577426): Support multiple arch variants - jars := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrcExcludes(ctx, i.properties.Jars, []string(nil))) + var jars bazel.LabelListAttribute + archVariantProps := i.GetArchVariantProperties(ctx, &ImportProperties{}) + for axis, configToProps := range archVariantProps { + for config, _props := range configToProps { + if archProps, ok := _props.(*ImportProperties); ok { + archJars := android.BazelLabelForModuleSrcExcludes(ctx, archProps.Jars, []string(nil)) + jars.SetSelectValue(axis, config, archJars) + } + } + } attrs := &bazelJavaImportAttributes{ Jars: jars, diff --git a/java/java_test.go b/java/java_test.go index f095c5e48..4c9382413 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -973,7 +973,7 @@ func TestTurbine(t *testing.T) { fooHeaderJar := filepath.Join("out", "soong", ".intermediates", "foo", "android_common", "turbine-combined", "foo.jar") barTurbineJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine", "bar.jar") - android.AssertStringDoesContain(t, "bar turbine classpath", barTurbine.Args["classpath"], fooHeaderJar) + android.AssertStringDoesContain(t, "bar turbine classpath", barTurbine.Args["turbineFlags"], fooHeaderJar) android.AssertStringDoesContain(t, "bar javac classpath", barJavac.Args["classpath"], fooHeaderJar) android.AssertPathsRelativeToTopEquals(t, "bar turbine combineJar", []string{barTurbineJar, fooHeaderJar}, barTurbineCombined.Inputs) android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "prebuilts/sdk/14/public/android.jar") diff --git a/java/jdeps.go b/java/jdeps.go index eff9a3174..373433517 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -71,6 +71,8 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars) dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars) dpInfo.Paths = android.FirstUniqueStrings(dpInfo.Paths) + dpInfo.Static_libs = android.FirstUniqueStrings(dpInfo.Static_libs) + dpInfo.Libs = android.FirstUniqueStrings(dpInfo.Libs) moduleInfos[name] = dpInfo mkProvider, ok := module.(android.AndroidMkDataProvider) diff --git a/java/kotlin.go b/java/kotlin.go index e4f1bc198..eff5bb53f 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -28,16 +28,20 @@ import ( var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports{Goma: true}, blueprint.RuleParams{ - Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + - `mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` + + Command: `rm -rf "$classesDir" "$headerClassesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + + `mkdir -p "$classesDir" "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + - `${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + - `$kotlincFlags -jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile ` + - `-kotlin-home $emptyDir && ` + - `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` + + `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` + + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + + ` $kotlincFlags -jvm-target $kotlinJvmTarget -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"`, CommandDeps: []string{ "${config.KotlincCmd}", @@ -48,15 +52,17 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports "${config.KotlinStdlibJar}", "${config.KotlinTrove4jJar}", "${config.KotlinAnnotationJar}", + "${config.KotlinAbiGenPluginJar}", "${config.GenKotlinBuildFileCmd}", "${config.SoongZipCmd}", "${config.ZipSyncCmd}", }, Rspfile: "$out.rsp", RspfileContent: `$in`, + Restat: true, }, "kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir", - "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name") + "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name") func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath { if len(commonSrcFiles) > 0 { @@ -75,7 +81,7 @@ func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Path } // kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile. -func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath, +func kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath, srcFiles, commonSrcFiles, srcJars android.Paths, flags javaBuilderFlags) { @@ -96,17 +102,20 @@ func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath, } ctx.Build(pctx, android.BuildParams{ - Rule: kotlinc, - Description: "kotlinc", - Output: outputFile, - Inputs: srcFiles, - Implicits: deps, + Rule: kotlinc, + Description: "kotlinc", + Output: outputFile, + ImplicitOutput: headerOutputFile, + Inputs: srcFiles, + Implicits: deps, Args: map[string]string{ "classpath": flags.kotlincClasspath.FormJavaClassPath(""), "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(), @@ -117,7 +126,7 @@ func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath, }) } -var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma: true}, +var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{Goma: true}, blueprint.RuleParams{ Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` + `mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` + @@ -125,19 +134,19 @@ var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma: `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + ` --srcs "$out.rsp" --srcs "$srcJarDir/list"` + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + - `${config.KotlincCmd} ${config.KaptSuppressJDK9Warnings} ${config.KotlincSuppressJDK9Warnings} ` + + `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` + + `${config.KaptSuppressJDK9Warnings} ${config.KotlincSuppressJDK9Warnings} ` + `${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 ` + `-P plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true ` + - `-P plugin:org.jetbrains.kotlin.kapt3:aptMode=stubsAndApt ` + + `-P plugin:org.jetbrains.kotlin.kapt3:aptMode=stubs ` + `-P plugin:org.jetbrains.kotlin.kapt3:javacArguments=$encodedJavacFlags ` + `$kaptProcessorPath ` + `$kaptProcessor ` + `-Xbuild-file=$kotlinBuildFile && ` + - `${config.SoongZipCmd} -jar -o $out -C $kaptDir/sources -D $kaptDir/sources && ` + - `${config.SoongZipCmd} -jar -o $classesJarOut -C $kaptDir/classes -D $kaptDir/classes && ` + + `${config.SoongZipCmd} -jar -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` + `rm -rf "$srcJarDir"`, CommandDeps: []string{ "${config.KotlincCmd}", @@ -195,13 +204,14 @@ func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile an kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName()) kotlinName = strings.ReplaceAll(kotlinName, "/", "__") + // First run kapt to generate .java stubs from .kt files + kaptStubsJar := android.PathForModuleOut(ctx, "kapt", "stubs.jar") ctx.Build(pctx, android.BuildParams{ - Rule: kapt, - Description: "kapt", - Output: srcJarOutputFile, - ImplicitOutput: resJarOutputFile, - Inputs: srcFiles, - Implicits: deps, + Rule: kaptStubs, + Description: "kapt stubs", + Output: kaptStubsJar, + Inputs: srcFiles, + Implicits: deps, Args: map[string]string{ "classpath": flags.kotlincClasspath.FormJavaClassPath(""), "kotlincFlags": flags.kotlincFlags, @@ -217,6 +227,11 @@ func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile an "classesJarOut": resJarOutputFile.String(), }, }) + + // Then run turbine to perform annotation processing on the stubs and any .java srcFiles. + javaSrcFiles := srcFiles.FilterByExt(".java") + turbineSrcJars := append(android.Paths{kaptStubsJar}, srcJars...) + TurbineApt(ctx, srcJarOutputFile, resJarOutputFile, javaSrcFiles, turbineSrcJars, flags) } // kapt converts a list of key, value pairs into a base64 encoded Java serialization, which is what kapt expects. diff --git a/java/kotlin_test.go b/java/kotlin_test.go index cac0af3b9..f9ff98229 100644 --- a/java/kotlin_test.go +++ b/java/kotlin_test.go @@ -45,6 +45,10 @@ func TestKotlin(t *testing.T) { fooKotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc") fooJavac := ctx.ModuleForTests("foo", "android_common").Rule("javac") fooJar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar") + fooHeaderJar := ctx.ModuleForTests("foo", "android_common").Output("turbine-combined/foo.jar") + + fooKotlincClasses := fooKotlinc.Output + fooKotlincHeaderClasses := fooKotlinc.ImplicitOutput if len(fooKotlinc.Inputs) != 2 || fooKotlinc.Inputs[0].String() != "a.java" || fooKotlinc.Inputs[1].String() != "b.kt" { @@ -55,17 +59,21 @@ func TestKotlin(t *testing.T) { t.Errorf(`foo inputs %v != ["a.java"]`, fooJavac.Inputs) } - if !strings.Contains(fooJavac.Args["classpath"], fooKotlinc.Output.String()) { + if !strings.Contains(fooJavac.Args["classpath"], fooKotlincHeaderClasses.String()) { t.Errorf("foo classpath %v does not contain %q", - fooJavac.Args["classpath"], fooKotlinc.Output.String()) + fooJavac.Args["classpath"], fooKotlincHeaderClasses.String()) } - if !inList(fooKotlinc.Output.String(), fooJar.Inputs.Strings()) { + if !inList(fooKotlincClasses.String(), fooJar.Inputs.Strings()) { t.Errorf("foo jar inputs %v does not contain %q", - fooJar.Inputs.Strings(), fooKotlinc.Output.String()) + fooJar.Inputs.Strings(), fooKotlincClasses.String()) + } + + if !inList(fooKotlincHeaderClasses.String(), fooHeaderJar.Inputs.Strings()) { + t.Errorf("foo header jar inputs %v does not contain %q", + fooHeaderJar.Inputs.Strings(), fooKotlincHeaderClasses.String()) } - fooHeaderJar := ctx.ModuleForTests("foo", "android_common").Output("turbine-combined/foo.jar") bazHeaderJar := ctx.ModuleForTests("baz", "android_common").Output("turbine-combined/baz.jar") barKotlinc := ctx.ModuleForTests("bar", "android_common").Rule("kotlinc") @@ -117,51 +125,71 @@ func TestKapt(t *testing.T) { buildOS := ctx.Config().BuildOS.String() - kapt := ctx.ModuleForTests("foo", "android_common").Rule("kapt") - kotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc") - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") + foo := ctx.ModuleForTests("foo", "android_common") + kaptStubs := foo.Rule("kapt") + turbineApt := foo.Description("turbine apt") + kotlinc := foo.Rule("kotlinc") + javac := foo.Rule("javac") bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String() baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String() // Test that the kotlin and java sources are passed to kapt and kotlinc - if len(kapt.Inputs) != 2 || kapt.Inputs[0].String() != "a.java" || kapt.Inputs[1].String() != "b.kt" { - t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kapt.Inputs) + if len(kaptStubs.Inputs) != 2 || kaptStubs.Inputs[0].String() != "a.java" || kaptStubs.Inputs[1].String() != "b.kt" { + t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kaptStubs.Inputs) } if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" { t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs) } - // Test that only the java sources are passed to javac + // Test that only the java sources are passed to turbine-apt and javac + if len(turbineApt.Inputs) != 1 || turbineApt.Inputs[0].String() != "a.java" { + t.Errorf(`foo turbine apt inputs %v != ["a.java"]`, turbineApt.Inputs) + } if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" { t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs) } - // Test that the kapt srcjar is a dependency of kotlinc and javac rules - if !inList(kapt.Output.String(), kotlinc.Implicits.Strings()) { - t.Errorf("expected %q in kotlinc implicits %v", kapt.Output.String(), kotlinc.Implicits.Strings()) + // Test that the kapt stubs jar is a dependency of turbine-apt + if !inList(kaptStubs.Output.String(), turbineApt.Implicits.Strings()) { + t.Errorf("expected %q in turbine-apt implicits %v", kaptStubs.Output.String(), kotlinc.Implicits.Strings()) + } + + // Test that the turbine-apt srcjar is a dependency of kotlinc and javac rules + if !inList(turbineApt.Output.String(), kotlinc.Implicits.Strings()) { + t.Errorf("expected %q in kotlinc implicits %v", turbineApt.Output.String(), kotlinc.Implicits.Strings()) } - if !inList(kapt.Output.String(), javac.Implicits.Strings()) { - t.Errorf("expected %q in javac implicits %v", kapt.Output.String(), javac.Implicits.Strings()) + if !inList(turbineApt.Output.String(), javac.Implicits.Strings()) { + t.Errorf("expected %q in javac implicits %v", turbineApt.Output.String(), javac.Implicits.Strings()) } - // Test that the kapt srcjar is extracted by the kotlinc and javac rules - if kotlinc.Args["srcJars"] != kapt.Output.String() { - t.Errorf("expected %q in kotlinc srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"]) + // Test that the turbine-apt srcjar is extracted by the kotlinc and javac rules + if kotlinc.Args["srcJars"] != turbineApt.Output.String() { + t.Errorf("expected %q in kotlinc srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"]) } - if javac.Args["srcJars"] != kapt.Output.String() { - t.Errorf("expected %q in javac srcjars %v", kapt.Output.String(), kotlinc.Args["srcJars"]) + if javac.Args["srcJars"] != turbineApt.Output.String() { + t.Errorf("expected %q in javac srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"]) } // Test that the processors are passed to kapt expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar + " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz - if kapt.Args["kaptProcessorPath"] != expectedProcessorPath { - t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"]) + if kaptStubs.Args["kaptProcessorPath"] != expectedProcessorPath { + t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kaptStubs.Args["kaptProcessorPath"]) } expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz" - if kapt.Args["kaptProcessor"] != expectedProcessor { - t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"]) + if kaptStubs.Args["kaptProcessor"] != expectedProcessor { + t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kaptStubs.Args["kaptProcessor"]) + } + + // Test that the processors are passed to turbine-apt + expectedProcessorPath = "--processorpath " + bar + " " + baz + if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessorPath) { + t.Errorf("expected turbine-apt processorpath %q, got %q", expectedProcessorPath, turbineApt.Args["turbineFlags"]) + } + expectedProcessor = "--processors com.bar com.baz" + if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessor) { + t.Errorf("expected turbine-apt processor %q, got %q", expectedProcessor, turbineApt.Args["turbineFlags"]) } // Test that the processors are not passed to javac diff --git a/java/lint.go b/java/lint.go index 7845c336b..e97c9c225 100644 --- a/java/lint.go +++ b/java/lint.go @@ -102,12 +102,12 @@ type lintOutputsIntf interface { lintOutputs() *lintOutputs } -type lintDepSetsIntf interface { +type LintDepSetsIntf interface { LintDepSets() LintDepSets // Methods used to propagate strict_updatability_linting values. - getStrictUpdatabilityLinting() bool - setStrictUpdatabilityLinting(bool) + GetStrictUpdatabilityLinting() bool + SetStrictUpdatabilityLinting(bool) } type LintDepSets struct { @@ -158,15 +158,15 @@ func (l *linter) LintDepSets() LintDepSets { return l.outputs.depSets } -func (l *linter) getStrictUpdatabilityLinting() bool { +func (l *linter) GetStrictUpdatabilityLinting() bool { return BoolDefault(l.properties.Lint.Strict_updatability_linting, false) } -func (l *linter) setStrictUpdatabilityLinting(strictLinting bool) { +func (l *linter) SetStrictUpdatabilityLinting(strictLinting bool) { l.properties.Lint.Strict_updatability_linting = &strictLinting } -var _ lintDepSetsIntf = (*linter)(nil) +var _ LintDepSetsIntf = (*linter)(nil) var _ lintOutputsIntf = (*linter)(nil) @@ -273,7 +273,7 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks) cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks) - if l.getStrictUpdatabilityLinting() { + if l.GetStrictUpdatabilityLinting() { // Verify the module does not baseline issues that endanger safe updatability. if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() { cmd.FlagWithInput("--baseline ", baselinePath.Path()) @@ -382,7 +382,7 @@ func (l *linter) lint(ctx android.ModuleContext) { depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml) ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) { - if depLint, ok := dep.(lintDepSetsIntf); ok { + if depLint, ok := dep.(LintDepSetsIntf); ok { depSetsBuilder.Transitive(depLint.LintDepSets()) } }) @@ -660,10 +660,10 @@ func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android // Enforce the strict updatability linting to all applicable transitive dependencies. func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) { m := ctx.Module() - if d, ok := m.(lintDepSetsIntf); ok && d.getStrictUpdatabilityLinting() { + if d, ok := m.(LintDepSetsIntf); ok && d.GetStrictUpdatabilityLinting() { ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) { - if a, ok := d.(lintDepSetsIntf); ok { - a.setStrictUpdatabilityLinting(true) + if a, ok := d.(LintDepSetsIntf); ok { + a.SetStrictUpdatabilityLinting(true) } }) } diff --git a/java/plugin.go b/java/plugin.go index 4b174b930..123dbd4c0 100644 --- a/java/plugin.go +++ b/java/plugin.go @@ -58,27 +58,32 @@ type PluginProperties struct { } type pluginAttributes struct { - *javaLibraryAttributes - Processor_class *string - Target_compatible_with bazel.LabelListAttribute + *javaCommonAttributes + Deps bazel.LabelListAttribute + Processor_class *string } // ConvertWithBp2build is used to convert android_app to Bazel. func (p *Plugin) ConvertWithBp2build(ctx android.TopDownMutatorContext) { - libAttrs := p.convertLibraryAttrsBp2Build(ctx) - attrs := &pluginAttributes{ - libAttrs, - nil, - bazel.LabelListAttribute{}, - } + pluginName := p.Name() + commonAttrs, depLabels := p.convertLibraryAttrsBp2Build(ctx) + + deps := depLabels.Deps + deps.Append(depLabels.StaticDeps) + var processorClass *string if p.pluginProperties.Processor_class != nil { - attrs.Processor_class = p.pluginProperties.Processor_class + processorClass = p.pluginProperties.Processor_class + } + + attrs := &pluginAttributes{ + javaCommonAttributes: commonAttrs, + Deps: deps, + Processor_class: processorClass, } props := bazel.BazelTargetModuleProperties{ Rule_class: "java_plugin", } - - ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: p.Name()}, attrs) + ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: pluginName}, attrs) } diff --git a/java/sdk_library.go b/java/sdk_library.go index bfdfffcd9..c37ed1a27 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -2362,17 +2362,17 @@ func (module *SdkLibraryImport) LintDepSets() LintDepSets { } } -func (module *SdkLibraryImport) getStrictUpdatabilityLinting() bool { +func (module *SdkLibraryImport) GetStrictUpdatabilityLinting() bool { if module.implLibraryModule == nil { return false } else { - return module.implLibraryModule.getStrictUpdatabilityLinting() + return module.implLibraryModule.GetStrictUpdatabilityLinting() } } -func (module *SdkLibraryImport) setStrictUpdatabilityLinting(strictLinting bool) { +func (module *SdkLibraryImport) SetStrictUpdatabilityLinting(strictLinting bool) { if module.implLibraryModule != nil { - module.implLibraryModule.setStrictUpdatabilityLinting(strictLinting) + module.implLibraryModule.SetStrictUpdatabilityLinting(strictLinting) } } diff --git a/java/testing.go b/java/testing.go index 82aa29b61..4000334b5 100644 --- a/java/testing.go +++ b/java/testing.go @@ -70,6 +70,10 @@ var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixtu defaultJavaDir + "/framework/aidl": nil, // Needed for various deps defined in GatherRequiredDepsForTest() defaultJavaDir + "/a.java": nil, + + // Needed for R8 rules on apps + "build/make/core/proguard.flags": nil, + "build/make/core/proguard_basic_keeps.flags": nil, }.AddToFixture(), // The java default module definitions. android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()), |