diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/Android.bp | 4 | ||||
| -rw-r--r-- | java/aar.go | 9 | ||||
| -rw-r--r-- | java/androidmk.go | 3 | ||||
| -rw-r--r-- | java/app_import.go | 27 | ||||
| -rw-r--r-- | java/app_import_test.go | 63 | ||||
| -rw-r--r-- | java/boot_image.go | 4 | ||||
| -rw-r--r-- | java/builder.go | 11 | ||||
| -rw-r--r-- | java/config/Android.bp | 4 | ||||
| -rw-r--r-- | java/device_host_converter.go | 29 | ||||
| -rw-r--r-- | java/dex.go | 5 | ||||
| -rw-r--r-- | java/dexpreopt.go | 5 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars.go | 5 | ||||
| -rw-r--r-- | java/dexpreopt_config.go | 4 | ||||
| -rw-r--r-- | java/droiddoc.go | 27 | ||||
| -rw-r--r-- | java/hiddenapi.go | 198 | ||||
| -rw-r--r-- | java/hiddenapi_singleton.go | 66 | ||||
| -rw-r--r-- | java/hiddenapi_singleton_test.go | 82 | ||||
| -rw-r--r-- | java/java.go | 299 | ||||
| -rw-r--r-- | java/java_test.go | 105 | ||||
| -rw-r--r-- | java/jdeps.go | 5 | ||||
| -rw-r--r-- | java/lint.go | 23 | ||||
| -rw-r--r-- | java/prebuilt_apis.go | 36 | ||||
| -rw-r--r-- | java/proto.go | 2 | ||||
| -rw-r--r-- | java/robolectric.go | 16 | ||||
| -rw-r--r-- | java/sdk.go | 31 | ||||
| -rw-r--r-- | java/sdk_library.go | 22 | ||||
| -rw-r--r-- | java/system_modules.go | 4 | ||||
| -rw-r--r-- | java/testing.go | 9 |
28 files changed, 815 insertions, 283 deletions
diff --git a/java/Android.bp b/java/Android.bp index 364566a8b..9bfd009c6 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-java", pkgPath: "android/soong/java", diff --git a/java/aar.go b/java/aar.go index e3ad252fd..ac7ae2518 100644 --- a/java/aar.go +++ b/java/aar.go @@ -28,7 +28,6 @@ import ( ) type AndroidLibraryDependency interface { - Dependency ExportPackage() android.Path ExportedProguardFlagFiles() android.Paths ExportedRRODirs() []rroDir @@ -796,9 +795,13 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile, linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil) -} -var _ Dependency = (*AARImport)(nil) + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(a.classpathFile), + ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile), + ImplementationJars: android.PathsIfNonNil(a.classpathFile), + }) +} func (a *AARImport) HeaderJars() android.Paths { return android.Paths{a.classpathFile} diff --git a/java/androidmk.go b/java/androidmk.go index 21f3012a4..6e7c437ab 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -646,6 +646,9 @@ func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled) } entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel()) + if Bool(a.properties.Export_package_resources) { + entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.outputFile) + } }, }, }} diff --git a/java/app_import.go b/java/app_import.go index 6f21bfbbf..59eb10a9b 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -92,6 +92,10 @@ type AndroidAppImportProperties struct { // Optional name for the installed app. If unspecified, it is derived from the module name. Filename *string + + // If set, create package-export.apk, which other packages can + // use to get PRODUCT-agnostic resource data like IDs and type definitions. + Export_package_resources *bool } func (a *AndroidAppImport) IsInstallable() bool { @@ -142,13 +146,17 @@ func MergePropertiesFromVariant(ctx android.EarlyModuleContext, } } +func (a *AndroidAppImport) isPrebuiltFrameworkRes() bool { + return a.Name() == "prebuilt_framework-res" +} + func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { cert := android.SrcIsModule(String(a.properties.Certificate)) if cert != "" { ctx.AddDependency(ctx.Module(), certificateTag, cert) } - a.usesLibrary.deps(ctx, true) + a.usesLibrary.deps(ctx, !a.isPrebuiltFrameworkRes()) } func (a *AndroidAppImport) uncompressEmbeddedJniLibs( @@ -247,7 +255,12 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath) var installDir android.InstallPath - if Bool(a.properties.Privileged) { + + if a.isPrebuiltFrameworkRes() { + // framework-res.apk is installed as system/framework/framework-res.apk + installDir = android.PathForModuleInstall(ctx, "framework") + a.preprocessed = true + } else if Bool(a.properties.Privileged) { installDir = android.PathForModuleInstall(ctx, "priv-app", a.BaseModuleName()) } else if ctx.InstallInTestcases() { installDir = android.PathForModuleInstall(ctx, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch()) @@ -275,7 +288,15 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // TODO: Handle EXTERNAL // Sign or align the package if package has not been preprocessed - if a.preprocessed { + + if a.isPrebuiltFrameworkRes() { + a.outputFile = srcApk + certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) + if len(certificates) != 1 { + ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates) + } + a.certificate = certificates[0] + } else if a.preprocessed { a.outputFile = srcApk a.certificate = PresignedCertificate } else if !Bool(a.properties.Presigned) { diff --git a/java/app_import_test.go b/java/app_import_test.go index 344d23b55..d7f69eb36 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -393,6 +393,69 @@ func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { } } +func TestAndroidAppImport_frameworkRes(t *testing.T) { + ctx, config := testJava(t, ` + android_app_import { + name: "framework-res", + certificate: "platform", + apk: "package-res.apk", + prefer: true, + export_package_resources: true, + // Disable dexpreopt and verify_uses_libraries check as the app + // contains no Java code to be dexpreopted. + enforce_uses_libs: false, + dex_preopt: { + enabled: false, + }, + } + `) + + mod := ctx.ModuleForTests("prebuilt_framework-res", "android_common").Module() + a := mod.(*AndroidAppImport) + + if !a.preprocessed { + t.Errorf("prebuilt framework-res is not preprocessed") + } + + expectedInstallPath := buildDir + "/target/product/test_device/system/framework/framework-res.apk" + + if a.dexpreopter.installPath.String() != expectedInstallPath { + t.Errorf("prebuilt framework-res installed to incorrect location, actual: %s, expected: %s", a.dexpreopter.installPath, expectedInstallPath) + + } + + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + + expectedPath := "." + // From apk property above, in the root of the source tree. + expectedPrebuiltModuleFile := "package-res.apk" + // Verify that the apk is preprocessed: The export package is the same + // as the prebuilt. + expectedSoongResourceExportPackage := expectedPrebuiltModuleFile + + actualPath := entries.EntryMap["LOCAL_PATH"] + actualPrebuiltModuleFile := entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"] + actualSoongResourceExportPackage := entries.EntryMap["LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE"] + + if len(actualPath) != 1 { + t.Errorf("LOCAL_PATH incorrect len %d", len(actualPath)) + } else if actualPath[0] != expectedPath { + t.Errorf("LOCAL_PATH mismatch, actual: %s, expected: %s", actualPath[0], expectedPath) + } + + if len(actualPrebuiltModuleFile) != 1 { + t.Errorf("LOCAL_PREBUILT_MODULE_FILE incorrect len %d", len(actualPrebuiltModuleFile)) + } else if actualPrebuiltModuleFile[0] != expectedPrebuiltModuleFile { + t.Errorf("LOCAL_PREBUILT_MODULE_FILE mismatch, actual: %s, expected: %s", actualPrebuiltModuleFile[0], expectedPrebuiltModuleFile) + } + + if len(actualSoongResourceExportPackage) != 1 { + t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE incorrect len %d", len(actualSoongResourceExportPackage)) + } else if actualSoongResourceExportPackage[0] != expectedSoongResourceExportPackage { + t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE mismatch, actual: %s, expected: %s", actualSoongResourceExportPackage[0], expectedSoongResourceExportPackage) + } +} + func TestAndroidTestImport(t *testing.T) { ctx, config := testJava(t, ` android_test_import { diff --git a/java/boot_image.go b/java/boot_image.go index 0a525b752..8a1e3c957 100644 --- a/java/boot_image.go +++ b/java/boot_image.go @@ -90,6 +90,10 @@ func (b *BootImageModule) DepIsInSameApex(ctx android.BaseModuleContext, dep and // The dex2oat tool is only needed for building and is not required in the apex. return false } + if android.IsMetaDependencyTag(tag) { + // Cross-cutting metadata dependencies are metadata. + return false + } panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag))) } diff --git a/java/builder.go b/java/builder.go index 995160d0e..22a891ae1 100644 --- a/java/builder.go +++ b/java/builder.go @@ -193,12 +193,19 @@ var ( jarjar = pctx.AndroidStaticRule("jarjar", blueprint.RuleParams{ - Command: "${config.JavaCmd} ${config.JavaVmFlags}" + + Command: "" + + // Jarjar doesn't exit with an error when the rules file contains a syntax error, + // leading to stale or missing files later in the build. Remove the output file + // before running jarjar. + "rm -f ${out} && " + + "${config.JavaCmd} ${config.JavaVmFlags}" + // b/146418363 Enable Android specific jarjar transformer to drop compat annotations // for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes // avoids adding new hiddenapis after jarjar'ing. " -DremoveAndroidCompatAnnotations=true" + - " -jar ${config.JarjarCmd} process $rulesFile $in $out", + " -jar ${config.JarjarCmd} process $rulesFile $in $out && " + + // Turn a missing output file into a ninja error + `[ -e ${out} ] || (echo "Missing output file"; exit 1)`, CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"}, }, "rulesFile") diff --git a/java/config/Android.bp b/java/config/Android.bp index 198352187..194e2c6ed 100644 --- a/java/config/Android.bp +++ b/java/config/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-java-config", pkgPath: "android/soong/java/config", diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 4914d74f6..ee7d01820 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -97,15 +97,15 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont } ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) { - if dep, ok := m.(Dependency); ok { - d.headerJars = append(d.headerJars, dep.HeaderJars()...) - d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...) - d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...) - d.resourceJars = append(d.resourceJars, dep.ResourceJars()...) - - srcJarArgs, srcJarDeps := dep.SrcJarArgs() - d.srcJarArgs = append(d.srcJarArgs, srcJarArgs...) - d.srcJarDeps = append(d.srcJarDeps, srcJarDeps...) + if ctx.OtherModuleHasProvider(m, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo) + d.headerJars = append(d.headerJars, dep.HeaderJars...) + d.implementationJars = append(d.implementationJars, dep.ImplementationJars...) + d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars...) + d.resourceJars = append(d.resourceJars, dep.ResourceJars...) + + d.srcJarArgs = append(d.srcJarArgs, dep.SrcJarArgs...) + d.srcJarDeps = append(d.srcJarDeps, dep.SrcJarDeps...) } else { ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) } @@ -131,9 +131,16 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont d.combinedHeaderJar = d.headerJars[0] } -} + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: d.headerJars, + ImplementationAndResourcesJars: d.implementationAndResourceJars, + ImplementationJars: d.implementationJars, + ResourceJars: d.resourceJars, + SrcJarArgs: d.srcJarArgs, + SrcJarDeps: d.srcJarDeps, + }) -var _ Dependency = (*DeviceHostConverter)(nil) +} func (d *DeviceHostConverter) HeaderJars() android.Paths { return d.headerJars diff --git a/java/dex.go b/java/dex.go index 24600c20f..e52fdb5d9 100644 --- a/java/dex.go +++ b/java/dex.go @@ -204,8 +204,9 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl // - prevent ProGuard stripping subclass in the support library that extends class added in the higher SDK version. // See b/20667396 var proguardRaiseDeps classpath - ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(dep android.Module) { - proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...) + ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) { + dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo) + proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...) }) r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) diff --git a/java/dexpreopt.go b/java/dexpreopt.go index da621003a..29c73c11f 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -129,8 +129,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) - buildPath := android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath - providesUsesLib := ctx.ModuleName() if ulib, ok := ctx.Module().(ProvidesUsesLib); ok { name := ulib.ProvidesUsesLib() @@ -146,7 +144,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr slimDexpreoptConfig := &dexpreopt.ModuleConfig{ Name: ctx.ModuleName(), DexLocation: dexLocation, - BuildPath: buildPath, EnforceUsesLibraries: d.enforceUsesLibs, ProvidesUsesLibrary: providesUsesLib, ClassLoaderContexts: d.classLoaderContexts, @@ -218,7 +215,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr dexpreoptConfig := &dexpreopt.ModuleConfig{ Name: ctx.ModuleName(), DexLocation: dexLocation, - BuildPath: buildPath, + BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath, DexPath: dexJarFile, ManifestPath: d.manifestFile, UncompressedDex: d.uncompressedDex, diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 2a7eb42dc..86b189558 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -435,6 +435,11 @@ func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonC // Inspect this module to see if it contains a bootclasspath dex jar. // Note that the same jar may occur in multiple modules. // This logic is tested in the apex package to avoid import cycle apex <-> java. +// +// This is similar to logic in isModuleInConfiguredList() so any changes needed here are likely to +// be needed there too. +// +// TODO(b/177892522): Avoid having to perform this type of check or if necessary dedup it. func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) { name := ctx.ModuleName(module) diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index c315124c9..282e9364e 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -82,10 +82,6 @@ func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName()) artModules := global.ArtApexJars - // With EMMA_INSTRUMENT_FRAMEWORK=true the Core libraries depend on jacoco. - if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { - artModules = artModules.Append("com.android.art", "jacocoagent") - } frameworkModules := global.BootJars.RemoveList(artModules) artSubdir := "apex/art_boot_images/javalib" diff --git a/java/droiddoc.go b/java/droiddoc.go index c74009ea4..8f1644c7f 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -470,8 +470,9 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { switch tag { case bootClasspathTag: - if dep, ok := module.(Dependency); ok { - deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...) + if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) + deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars...) } else if sm, ok := module.(SystemModulesProvider); ok { // A system modules dependency has been added to the bootclasspath // so add its libs to the bootclasspath. @@ -480,23 +481,23 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName())) } case libTag: - switch dep := module.(type) { - case SdkLibraryDependency: + if dep, ok := module.(SdkLibraryDependency); ok { deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) - case Dependency: - deps.classpath = append(deps.classpath, dep.HeaderJars()...) - deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) - case android.SourceFileProducer: + } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) + deps.classpath = append(deps.classpath, dep.HeaderJars...) + deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) + } else if dep, ok := module.(android.SourceFileProducer); ok { checkProducesJars(ctx, dep) deps.classpath = append(deps.classpath, dep.Srcs()...) - default: + } else { ctx.ModuleErrorf("depends on non-java module %q", otherName) } case java9LibTag: - switch dep := module.(type) { - case Dependency: - deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...) - default: + if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) + deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) + } else { ctx.ModuleErrorf("depends on non-java module %q", otherName) } case systemModulesTag: diff --git a/java/hiddenapi.go b/java/hiddenapi.go index eafbf5df0..f8e41c458 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -28,10 +28,39 @@ var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", bl }, "outFlag", "stubAPIFlags") type hiddenAPI struct { + // The name of the module as it would be used in the boot jars configuration, e.g. without any + // prebuilt_ prefix (if it is a prebuilt), without any "-hiddenapi" suffix if it just provides + // annotations and without any ".impl" suffix if it is a java_sdk_library implementation library. + configurationName string + + // True if the module containing this structure contributes to the hiddenapi information or has + // that information encoded within it. + active bool + + // Identifies the active module variant which will be used as the source of hiddenapi information. + // + // A class may be compiled into a number of different module variants each of which will need the + // hiddenapi information encoded into it and so will be marked as active. However, only one of + // them must be used as a source of information by hiddenapi otherwise it will end up with + // duplicate entries. That module will have primary=true. + // + // Note, that modules <x>-hiddenapi that provide additional annotation information for module <x> + // that is on the bootclasspath are marked as primary=true as they are the primary source of that + // annotation information. + primary bool + + // True if the module only contains additional annotations and so does not require hiddenapi + // information to be encoded in its dex file and should not be used to generate the + // hiddenAPISingletonPathsStruct.stubFlags file. + annotationsOnly bool + // The path to the dex jar that is in the boot class path. If this is nil then the associated // module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional // annotations for the <x> boot dex jar but which do not actually provide a boot dex jar // themselves. + // + // This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on + // this file so using the encoded dex jar here would result in a cycle in the ninja rules. bootDexJarPath android.Path // The path to the CSV file that contains mappings from Java signature to various flags derived @@ -89,59 +118,122 @@ type hiddenAPIIntf interface { var _ hiddenAPIIntf = (*hiddenAPI)(nil) -func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bool, dexJar android.OutputPath, - implementationJar android.Path, uncompressDex bool) android.OutputPath { - if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { - - // Modules whose names are of the format <x>-hiddenapi provide hiddenapi information - // for the boot jar module <x>. Otherwise, the module provides information for itself. - // Either way extract the name of the boot jar module. - bootJarName := strings.TrimSuffix(name, "-hiddenapi") - - // If this module is on the boot jars list (or providing information for a module - // on the list) then extract the hiddenapi information from it, and if necessary - // encode that information in the generated dex file. - // - // It is important that hiddenapi information is only gathered for/from modules on - // that are actually on the boot jars list because the runtime only enforces access - // to the hidden API for the bootclassloader. If information is gathered for modules - // not on the list then that will cause failures in the CtsHiddenApiBlacklist... - // tests. - if inList(bootJarName, ctx.Config().BootJars()) { - // Create ninja rules to generate various CSV files needed by hiddenapi and store the paths - // in the hiddenAPI structure. - h.hiddenAPIGenerateCSV(ctx, implementationJar) - - // If this module is actually on the boot jars list and not providing - // hiddenapi information for a module on the boot jars list then encode - // the gathered information in the generated dex file. - if name == bootJarName { - hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", name+".jar").OutputPath - - // More than one library with the same classes can be encoded but only one can - // be added to the global set of flags, otherwise it will result in duplicate - // classes which is an error. Therefore, only add the dex jar of one of them - // to the global set of flags. - if primary { - h.bootDexJarPath = dexJar - } - hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex) - dexJar = hiddenAPIJar - } +// Initialize the hiddenapi structure +func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, name string) { + // If hiddenapi processing is disabled treat this as inactive. + if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + return + } + + // Modules whose names are of the format <x>-hiddenapi provide hiddenapi information for the boot + // jar module <x>. Otherwise, the module provides information for itself. Either way extract the + // configurationName of the boot jar module. + configurationName := strings.TrimSuffix(name, "-hiddenapi") + h.configurationName = configurationName + + // It is important that hiddenapi information is only gathered for/from modules that are actually + // on the boot jars list because the runtime only enforces access to the hidden API for the + // bootclassloader. If information is gathered for modules not on the list then that will cause + // failures in the CtsHiddenApiBlocklist... tests. + h.active = inList(configurationName, ctx.Config().BootJars()) + if !h.active { + // The rest of the properties will be ignored if active is false. + return + } + + // If this module has a suffix of -hiddenapi then it only provides additional annotation + // information for a module on the boot jars list. + h.annotationsOnly = strings.HasSuffix(name, "-hiddenapi") + + // Determine whether this module is the primary module or not. + primary := true + + // A prebuilt module is only primary if it is preferred and conversely a source module is only + // primary if it has not been replaced by a prebuilt module. + module := ctx.Module() + if pi, ok := module.(android.PrebuiltInterface); ok { + if p := pi.Prebuilt(); p != nil { + primary = p.UsePrebuilt() } + } else { + // The only module that will pass a different name to its module name to this method is the + // implementation library of a java_sdk_library. It has a configuration name of <x> the same + // as its parent java_sdk_library but a module name of <x>.impl. It is not the primary module, + // the java_sdk_library with the name of <x> is. + primary = name == ctx.ModuleName() + + // A source module that has been replaced by a prebuilt can never be the primary module. + primary = primary && !module.IsReplacedByPrebuilt() + } + h.primary = primary +} + +// hiddenAPIExtractAndEncode is called by any module that could contribute to the hiddenapi +// processing. +// +// It ignores any module that has not had initHiddenApi() called on it and which is not in the boot +// jar list. +// +// Otherwise, it generates ninja rules to do the following: +// 1. Extract information needed for hiddenapi processing from the module and output it into CSV +// files. +// 2. Conditionally adds the supplied dex file to the list of files used to generate the +// hiddenAPISingletonPathsStruct.stubsFlag file. +// 3. Conditionally creates a copy of the supplied dex file into which it has encoded the hiddenapi +// flags and returns this instead of the supplied dex jar, otherwise simply returns the supplied +// dex jar. +func (h *hiddenAPI) hiddenAPIExtractAndEncode(ctx android.ModuleContext, dexJar android.OutputPath, + implementationJar android.Path, uncompressDex bool) android.OutputPath { + + if !h.active { + return dexJar + } + + h.hiddenAPIExtractInformation(ctx, dexJar, implementationJar) + + if !h.annotationsOnly { + hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", h.configurationName+".jar").OutputPath + + // Create a copy of the dex jar which has been encoded with hiddenapi flags. + hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex) + + // Use the encoded dex jar from here onwards. + dexJar = hiddenAPIJar } return dexJar } -func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar android.Path) { +// hiddenAPIExtractInformation generates ninja rules to extract the information from the classes +// jar, and outputs it to the appropriate module specific CSV file. +// +// It also makes the dex jar available for use when generating the +// hiddenAPISingletonPathsStruct.stubFlags. +func (h *hiddenAPI) hiddenAPIExtractInformation(ctx android.ModuleContext, dexJar, classesJar android.Path) { + if !h.active { + return + } + + // More than one library with the same classes may need to be encoded but only one should be + // used as a source of information for hidden API processing otherwise it will result in + // duplicate entries in the files. + if !h.primary { + return + } + + classesJars := android.Paths{classesJar} + ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) { + javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) + classesJars = append(classesJars, javaInfo.ImplementationJars...) + }) + stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv") ctx.Build(pctx, android.BuildParams{ Rule: hiddenAPIGenerateCSVRule, Description: "hiddenapi flags", - Input: classesJar, + Inputs: classesJars, Output: flagsCSV, Implicit: stubFlagsCSV, Args: map[string]string{ @@ -155,7 +247,7 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar a ctx.Build(pctx, android.BuildParams{ Rule: hiddenAPIGenerateCSVRule, Description: "hiddenapi metadata", - Input: classesJar, + Inputs: classesJars, Output: metadataCSV, Implicit: stubFlagsCSV, Args: map[string]string{ @@ -169,10 +261,15 @@ func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar a rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). BuiltTool("merge_csv"). - FlagWithInput("--zip_input=", classesJar). - FlagWithOutput("--output=", indexCSV) + Flag("--zip_input"). + FlagWithOutput("--output=", indexCSV). + Inputs(classesJars) rule.Build("merged-hiddenapi-index", "Merged Hidden API index") h.indexCSVPath = indexCSV + + // Save the unencoded dex jar so it can be used when generating the + // hiddenAPISingletonPathsStruct.stubFlags file. + h.bootDexJarPath = dexJar } var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{ @@ -245,3 +342,16 @@ func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath, TransformZipAlign(ctx, output, tmpOutput) } } + +type hiddenApiAnnotationsDependencyTag struct { + blueprint.BaseDependencyTag +} + +// Tag used to mark dependencies on java_library instances that contains Java source files whose +// sole purpose is to provide additional hiddenapi annotations. +var hiddenApiAnnotationsTag hiddenApiAnnotationsDependencyTag + +// Mark this tag so dependencies that use it are excluded from APEX contents. +func (t hiddenApiAnnotationsDependencyTag) ExcludeFromApexContents() {} + +var _ android.ExcludeFromApexContentsTag = hiddenApiAnnotationsTag diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index ccb874506..6341a3406 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -22,9 +22,13 @@ import ( ) func init() { - android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) - android.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) - android.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory) + RegisterHiddenApiSingletonComponents(android.InitRegistrationContext) +} + +func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) { + ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) + ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory) } type hiddenAPISingletonPathsStruct struct { @@ -213,9 +217,13 @@ func stubFlagsRule(ctx android.SingletonContext) { var bootDexJars android.Paths + // Get the configured non-updatable and updatable boot jars. + nonUpdatableBootJars := ctx.Config().NonUpdatableBootJars() + updatableBootJars := ctx.Config().UpdatableBootJars() + ctx.VisitAllModules(func(module android.Module) { // Collect dex jar paths for the modules listed above. - if j, ok := module.(Dependency); ok { + if j, ok := module.(UsesLibraryDependency); ok { name := ctx.ModuleName(module) for moduleList, pathList := range moduleListToPathList { if i := android.IndexList(name, *moduleList); i != -1 { @@ -227,11 +235,8 @@ func stubFlagsRule(ctx android.SingletonContext) { // Collect dex jar paths for modules that had hiddenapi encode called on them. if h, ok := module.(hiddenAPIIntf); ok { if jar := h.bootDexJar(); jar != nil { - // For a java lib included in an APEX, only take the one built for - // the platform variant, and skip the variants for APEXes. - // Otherwise, the hiddenapi tool will complain about duplicated classes - apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) - if !apexInfo.IsForPlatform() { + if !isModuleInConfiguredList(ctx, module, nonUpdatableBootJars) && + !isModuleInConfiguredList(ctx, module, updatableBootJars) { return } @@ -280,6 +285,47 @@ func stubFlagsRule(ctx android.SingletonContext) { rule.Build("hiddenAPIStubFlagsFile", "hiddenapi stub flags") } +// Checks to see whether the supplied module variant is in the list of boot jars. +// +// This is similar to logic in getBootImageJar() so any changes needed here are likely to be needed +// there too. +// +// TODO(b/179354495): Avoid having to perform this type of check or if necessary dedup it. +func isModuleInConfiguredList(ctx android.SingletonContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool { + name := ctx.ModuleName(module) + + // Strip a prebuilt_ prefix so that this can match a prebuilt module that has not been renamed. + name = android.RemoveOptionalPrebuiltPrefix(name) + + // Ignore any module that is not listed in the boot image configuration. + index := configuredBootJars.IndexOfJar(name) + if index == -1 { + return false + } + + // It is an error if the module is not an ApexModule. + if _, ok := module.(android.ApexModule); !ok { + ctx.Errorf("module %q configured in boot jars does not support being added to an apex", module) + return false + } + + apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) + + // Now match the apex part of the boot image configuration. + requiredApex := configuredBootJars.Apex(index) + if requiredApex == "platform" { + if len(apexInfo.InApexes) != 0 { + // A platform variant is required but this is for an apex so ignore it. + return false + } + } else if !apexInfo.InApexByBaseName(requiredApex) { + // An apex variant for a specific apex is required but this is the wrong apex. + return false + } + + return true +} + func prebuiltFlagsRule(ctx android.SingletonContext) android.Path { outputPath := hiddenAPISingletonPaths(ctx).flags inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-flags.csv") @@ -326,7 +372,7 @@ func flagsRule(ctx android.SingletonContext) android.Path { stubFlags := hiddenAPISingletonPaths(ctx).stubFlags rule.Command(). - Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")). + BuiltTool("generate_hiddenapi_lists"). FlagWithInput("--csv ", stubFlags). Inputs(flagsCSV). FlagWithInput("--unsupported ", diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index 0f9ef5841..4670d0311 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -15,11 +15,12 @@ package java import ( - "android/soong/android" "fmt" "strings" "testing" + "android/soong/android" + "github.com/google/blueprint/proptools" ) @@ -32,7 +33,7 @@ func testConfigWithBootJars(bp string, bootJars []string, prebuiltHiddenApiDir * func testContextWithHiddenAPI(config android.Config) *android.TestContext { ctx := testContext(config) - ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + RegisterHiddenApiSingletonComponents(ctx) return ctx } @@ -64,8 +65,8 @@ func TestHiddenAPISingleton(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } - `, []string{":foo"}, nil) + } + `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") @@ -75,6 +76,63 @@ func TestHiddenAPISingleton(t *testing.T) { } } +func TestHiddenAPIIndexSingleton(t *testing.T) { + ctx, _ := testHiddenAPIBootJars(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + + hiddenapi_additional_annotations: [ + "foo-hiddenapi-annotations", + ], + } + + java_library { + name: "foo-hiddenapi", + srcs: ["a.java"], + compile_dex: true, + } + + java_library { + name: "foo-hiddenapi-annotations", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: false, + } + + java_sdk_library { + name: "bar", + srcs: ["a.java"], + compile_dex: true, + } + `, []string{"platform:foo", "platform:bar"}, nil) + + hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index") + indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index") + CheckHiddenAPIRuleInputs(t, ` +.intermediates/bar/android_common/hiddenapi/index.csv +.intermediates/foo-hiddenapi/android_common/hiddenapi/index.csv +.intermediates/foo/android_common/hiddenapi/index.csv +`, + indexRule) + + // Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that + // creates the index.csv file. + foo := ctx.ModuleForTests("foo", "android_common") + indexParams := foo.Output("hiddenapi/index.csv") + CheckHiddenAPIRuleInputs(t, ` +.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar +.intermediates/foo/android_common/javac/foo.jar +`, indexParams) +} + func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { ctx, _ := testHiddenAPIBootJars(t, ` java_import { @@ -82,7 +140,7 @@ func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { jars: ["a.jar"], compile_dex: true, } - `, []string{":foo"}, nil) + `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") @@ -98,15 +156,15 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } + } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: false, - } - `, []string{":foo"}, nil) + } + `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") @@ -127,15 +185,15 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { name: "foo", srcs: ["a.java"], compile_dex: true, - } + } java_import { name: "foo", jars: ["a.jar"], compile_dex: true, prefer: true, - } - `, []string{":foo"}, nil) + } + `, []string{"platform:foo"}, nil) hiddenAPI := ctx.SingletonForTests("hiddenapi") hiddenapiRule := hiddenAPI.Rule("hiddenapi") @@ -236,7 +294,7 @@ func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { jars: ["a.jar"], compile_dex: true, } - `, []string{":foo"}, &prebuiltHiddenApiDir) + `, []string{"platform:foo"}, &prebuiltHiddenApiDir) expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv" expectedCpOutput := buildDir + "/hiddenapi/hiddenapi-flags.csv" diff --git a/java/java.go b/java/java.go index d49b64f66..dbfad029b 100644 --- a/java/java.go +++ b/java/java.go @@ -40,18 +40,21 @@ func init() { // Register sdk member types. android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType) + // Export implementation classes jar as part of the sdk. + exportImplementationClassesJar := func(_ android.SdkMemberContext, j *Library) android.Path { + implementationJars := j.ImplementationAndResourcesJars() + if len(implementationJars) != 1 { + panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name())) + } + return implementationJars[0] + } + // Register java implementation libraries for use only in module_exports (not sdk). android.RegisterSdkMemberType(&librarySdkMemberType{ android.SdkMemberTypeBase{ PropertyName: "java_libs", }, - func(_ android.SdkMemberContext, j *Library) android.Path { - implementationJars := j.ImplementationAndResourcesJars() - if len(implementationJars) != 1 { - panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name())) - } - return implementationJars[0] - }, + exportImplementationClassesJar, sdkSnapshotFilePathForJar, copyEverythingToSnapshot, }) @@ -72,19 +75,11 @@ func init() { PropertyName: "java_boot_libs", SupportsSdk: true, }, - func(ctx android.SdkMemberContext, j *Library) android.Path { - // Java boot libs are only provided in the SDK to provide access to their dex implementation - // jar for use by dexpreopting and boot jars package check. They do not need to provide an - // actual implementation jar but the java_import will need a file that exists so just copy an - // empty file. Any attempt to use that file as a jar will cause a build error. - return ctx.SnapshotBuilder().EmptyFile() - }, - func(osPrefix, name string) string { - // Create a special name for the implementation jar to try and provide some useful information - // to a developer that attempts to compile against this. - // TODO(b/175714559): Provide a proper error message in Soong not ninja. - return filepath.Join(osPrefix, "java_boot_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix) - }, + // Temporarily export implementation classes jar for java_boot_libs as it is required for the + // hiddenapi processing. + // TODO(b/179354495): Revert once hiddenapi processing has been modularized. + exportImplementationClassesJar, + sdkSnapshotFilePathForJar, onlyCopyJarToSnapshot, }) @@ -303,6 +298,9 @@ type CompilerProperties struct { // If true, package the kotlin stdlib into the jar. Defaults to true. Static_kotlin_stdlib *bool `android:"arch_variant"` + + // A list of java_library instances that provide additional hiddenapi annotations for the library. + Hiddenapi_additional_annotations []string } type CompilerDeviceProperties struct { @@ -538,6 +536,53 @@ func (j *Module) OutputFiles(tag string) (android.Paths, error) { var _ android.OutputFileProducer = (*Module)(nil) +// JavaInfo contains information about a java module for use by modules that depend on it. +type JavaInfo struct { + // HeaderJars is a list of jars that can be passed as the javac classpath in order to link + // against this module. If empty, ImplementationJars should be used instead. + HeaderJars android.Paths + + // ImplementationAndResourceJars is a list of jars that contain the implementations of classes + // in the module as well as any resources included in the module. + ImplementationAndResourcesJars android.Paths + + // ImplementationJars is a list of jars that contain the implementations of classes in the + //module. + ImplementationJars android.Paths + + // ResourceJars is a list of jars that contain the resources included in the module. + ResourceJars android.Paths + + // AidlIncludeDirs is a list of directories that should be passed to the aidl tool when + // depending on this module. + AidlIncludeDirs android.Paths + + // SrcJarArgs is a list of arguments to pass to soong_zip to package the sources of this + // module. + SrcJarArgs []string + + // SrcJarDeps is a list of paths to depend on when packaging the sources of this module. + SrcJarDeps android.Paths + + // ExportedPlugins is a list of paths that should be used as annotation processors for any + // module that depends on this module. + ExportedPlugins android.Paths + + // ExportedPluginClasses is a list of classes that should be run as annotation processors for + // any module that depends on this module. + ExportedPluginClasses []string + + // ExportedPluginDisableTurbine is true if this module's annotation processors generate APIs, + // requiring disbling turbine for any modules that depend on it. + ExportedPluginDisableTurbine bool + + // JacocoReportClassesFile is the path to a jar containing uninstrumented classes that will be + // instrumented by jacoco. + JacocoReportClassesFile android.Path +} + +var JavaInfoProvider = blueprint.NewProvider(JavaInfo{}) + // Methods that need to be implemented for a module that is added to apex java_libs property. type ApexDependency interface { HeaderJars() android.Paths @@ -551,18 +596,6 @@ type UsesLibraryDependency interface { ClassLoaderContexts() dexpreopt.ClassLoaderContextMap } -type Dependency interface { - ApexDependency - UsesLibraryDependency - ImplementationJars() android.Paths - ResourceJars() android.Paths - AidlIncludeDirs() android.Paths - ExportedPlugins() (android.Paths, []string, bool) - SrcJarArgs() ([]string, android.Paths) - BaseModuleName() string - JacocoReportClassesFile() android.Path -} - type xref interface { XrefJavaFiles() android.Paths } @@ -810,6 +843,9 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { libDeps := ctx.AddVariationDependencies(nil, libTag, rewriteSyspropLibs(j.properties.Libs, "libs")...) ctx.AddVariationDependencies(nil, staticLibTag, rewriteSyspropLibs(j.properties.Static_libs, "static_libs")...) + // Add dependency on libraries that provide additional hidden api annotations. + ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...) + if ctx.DeviceConfig().VndkVersion() != "" && ctx.Config().EnforceInterPartitionJavaSdkLibrary() { // Require java_sdk_library at inter-partition java dependency to ensure stable // interface between partitions. If inter-partition java_library dependency is detected, @@ -978,6 +1014,7 @@ type linkType int const ( // TODO(jiyong) rename these for better readability. Make the allowed // and disallowed link types explicit + // order is important here. See rank() javaCore linkType = iota javaSdk javaSystem @@ -986,6 +1023,31 @@ const ( javaPlatform ) +func (lt linkType) String() string { + switch lt { + case javaCore: + return "core Java API" + case javaSdk: + return "Android API" + case javaSystem: + return "system API" + case javaModule: + return "module API" + case javaSystemServer: + return "system server API" + case javaPlatform: + return "private API" + default: + panic(fmt.Errorf("unrecognized linktype: %v", lt)) + } +} + +// rank determins the total order among linkTypes. A link type of rank A can link to another link +// type of rank B only when B <= A +func (lt linkType) rank() int { + return int(lt) +} + type linkTypeContext interface { android.Module getLinkType(name string) (ret linkType, stubs bool) @@ -1045,44 +1107,13 @@ func checkLinkType(ctx android.ModuleContext, from *Module, to linkTypeContext, return } otherLinkType, _ := to.getLinkType(ctx.OtherModuleName(to)) - commonMessage := " In order to fix this, consider adjusting sdk_version: OR platform_apis: " + - "property of the source or target module so that target module is built with the same " + - "or smaller API set when compared to the source." - switch myLinkType { - case javaCore: - if otherLinkType != javaCore { - ctx.ModuleErrorf("compiles against core Java API, but dependency %q is compiling against non-core Java APIs."+commonMessage, - ctx.OtherModuleName(to)) - } - break - case javaSdk: - if otherLinkType != javaCore && otherLinkType != javaSdk { - ctx.ModuleErrorf("compiles against Android API, but dependency %q is compiling against non-public Android API."+commonMessage, - ctx.OtherModuleName(to)) - } - break - case javaSystem: - if otherLinkType == javaPlatform || otherLinkType == javaModule || otherLinkType == javaSystemServer { - ctx.ModuleErrorf("compiles against system API, but dependency %q is compiling against private API."+commonMessage, - ctx.OtherModuleName(to)) - } - break - case javaModule: - if otherLinkType == javaPlatform || otherLinkType == javaSystemServer { - ctx.ModuleErrorf("compiles against module API, but dependency %q is compiling against private API."+commonMessage, - ctx.OtherModuleName(to)) - } - break - case javaSystemServer: - if otherLinkType == javaPlatform { - ctx.ModuleErrorf("compiles against system server API, but dependency %q is compiling against private API."+commonMessage, - ctx.OtherModuleName(to)) - } - break - case javaPlatform: - // no restriction on link-type - break + if myLinkType.rank() < otherLinkType.rank() { + ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+ + "In order to fix this, consider adjusting sdk_version: OR platform_apis: "+ + "property of the source or target module so that target module is built "+ + "with the same or smaller API set when compared to the source.", + myLinkType, ctx.OtherModuleName(to), otherLinkType) } } @@ -1116,44 +1147,42 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { return } - switch dep := module.(type) { - case SdkLibraryDependency: + if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } - case Dependency: + } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) switch tag { case bootClasspathTag: - deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...) + deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...) case libTag, instrumentationForTag: - deps.classpath = append(deps.classpath, dep.HeaderJars()...) - deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) - pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins() - addPlugins(&deps, pluginJars, pluginClasses...) - deps.disableTurbine = deps.disableTurbine || disableTurbine + deps.classpath = append(deps.classpath, dep.HeaderJars...) + deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) + addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...) + deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine case java9LibTag: - deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...) + deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) case staticLibTag: - deps.classpath = append(deps.classpath, dep.HeaderJars()...) - deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...) - deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...) - deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...) - deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) - pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins() - addPlugins(&deps, pluginJars, pluginClasses...) + deps.classpath = append(deps.classpath, dep.HeaderJars...) + deps.staticJars = append(deps.staticJars, dep.ImplementationJars...) + deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars...) + deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars...) + deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) + addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...) // Turbine doesn't run annotation processors, so any module that uses an // annotation processor that generates API is incompatible with the turbine // optimization. - deps.disableTurbine = deps.disableTurbine || disableTurbine + deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine case pluginTag: - if plugin, ok := dep.(*Plugin); ok { + if plugin, ok := module.(*Plugin); ok { if plugin.pluginProperties.Processor_class != nil { - addPlugins(&deps, plugin.ImplementationAndResourcesJars(), *plugin.pluginProperties.Processor_class) + addPlugins(&deps, dep.ImplementationAndResourcesJars, *plugin.pluginProperties.Processor_class) } else { - addPlugins(&deps, plugin.ImplementationAndResourcesJars()) + addPlugins(&deps, dep.ImplementationAndResourcesJars) } // Turbine doesn't run annotation processors, so any module that uses an // annotation processor that generates API is incompatible with the turbine @@ -1163,14 +1192,14 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName) } case errorpronePluginTag: - if plugin, ok := dep.(*Plugin); ok { - deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, plugin.ImplementationAndResourcesJars()...) + if _, ok := module.(*Plugin); ok { + deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, dep.ImplementationAndResourcesJars...) } else { ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName) } case exportedPluginTag: - if plugin, ok := dep.(*Plugin); ok { - j.exportedPluginJars = append(j.exportedPluginJars, plugin.ImplementationAndResourcesJars()...) + if plugin, ok := module.(*Plugin); ok { + j.exportedPluginJars = append(j.exportedPluginJars, dep.ImplementationAndResourcesJars...) if plugin.pluginProperties.Processor_class != nil { j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.pluginProperties.Processor_class) } @@ -1182,12 +1211,11 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } case kotlinStdlibTag: - deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...) + deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars...) case kotlinAnnotationsTag: - deps.kotlinAnnotations = dep.HeaderJars() + deps.kotlinAnnotations = dep.HeaderJars } - - case android.SourceFileProducer: + } else if dep, ok := module.(android.SourceFileProducer); ok { switch tag { case libTag: checkProducesJars(ctx, dep) @@ -1198,7 +1226,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.staticJars = append(deps.staticJars, dep.Srcs()...) deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...) } - default: + } else { switch tag { case bootClasspathTag: // If a system modules dependency has been added to the bootclasspath @@ -1803,14 +1831,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { return } - configurationName := j.ConfigurationName() - primary := configurationName == ctx.ModuleName() - // If the prebuilt is being used rather than the from source, skip this - // module to prevent duplicated classes - primary = primary && !j.IsReplacedByPrebuilt() - // Hidden API CSV generation and dex encoding - dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile, + dexOutputFile = j.hiddenAPIExtractAndEncode(ctx, dexOutputFile, j.implementationJarFile, proptools.Bool(j.dexProperties.Uncompress_dex)) // merge dex jar with resources if necessary @@ -1871,6 +1893,20 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { ctx.CheckbuildFile(outputFile) + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(j.headerJarFile), + ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar), + ImplementationJars: android.PathsIfNonNil(j.implementationJarFile), + ResourceJars: android.PathsIfNonNil(j.resourceJar), + AidlIncludeDirs: j.exportAidlIncludeDirs, + SrcJarArgs: j.srcJarArgs, + SrcJarDeps: j.srcJarDeps, + ExportedPlugins: j.exportedPluginJars, + ExportedPluginClasses: j.exportedPluginClasses, + ExportedPluginDisableTurbine: j.exportedDisableTurbine, + JacocoReportClassesFile: j.jacocoReportClassesFile, + }) + // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource j.outputFile = outputFile.WithoutRel() } @@ -1978,8 +2014,6 @@ func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, return instrumentedJar } -var _ Dependency = (*Module)(nil) - func (j *Module) HeaderJars() android.Paths { if j.headerJarFile == nil { return nil @@ -2095,6 +2129,11 @@ func (j *Module) Stem() string { return proptools.StringDefault(j.deviceProperties.Stem, j.Name()) } +// ConfigurationName returns the name of the module as used in build configuration. +// +// This is usually the same as BaseModuleName() except for the <x>.impl libraries created by +// java_sdk_library in which case this is the BaseModuleName() without the ".impl" suffix, +// i.e. just <x>. func (j *Module) ConfigurationName() string { return proptools.StringDefault(j.deviceProperties.ConfigurationName, j.BaseModuleName()) } @@ -2154,6 +2193,11 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo } func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Initialize the hiddenapi structure. Pass in the configuration name rather than the module name + // so the hidden api will encode the <x>.impl java_ library created by java_sdk_library just as it + // would the <x> library if <x> was configured as a boot jar. + j.initHiddenAPI(ctx, j.ConfigurationName()) + apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { j.hideApexVariantFromMake = true @@ -2687,9 +2731,10 @@ func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) { } func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) { - if ctx.Arch().ArchType == android.Common { + if ctx.Arch().ArchType == android.Common || ctx.BazelConversionMode() { j.deps(ctx) - } else { + } + if ctx.Arch().ArchType != android.Common || ctx.BazelConversionMode() { // These dependencies ensure the host installation rules will install the jar file and // the jni libraries when the wrapper is installed. ctx.AddVariationDependencies(nil, jniInstallTag, j.binaryProperties.Jni_libs...) @@ -2853,6 +2898,9 @@ func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { } func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Initialize the hiddenapi structure. + j.initHiddenAPI(ctx, j.BaseModuleName()) + if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() { j.hideApexVariantFromMake = true } @@ -2877,15 +2925,15 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.VisitDirectDeps(func(module android.Module) { tag := ctx.OtherModuleDependencyTag(module) - switch dep := module.(type) { - case Dependency: + if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) switch tag { case libTag, staticLibTag: - flags.classpath = append(flags.classpath, dep.HeaderJars()...) + flags.classpath = append(flags.classpath, dep.HeaderJars...) case bootClasspathTag: - flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...) + flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...) } - case SdkLibraryDependency: + } else if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) @@ -2921,8 +2969,10 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Get the path of the dex implementation jar from the `deapexer` module. di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) - j.dexJarFile = di.PrebuiltExportPath(j.BaseModuleName(), ".dexjar") - if j.dexJarFile == nil { + if dexOutputPath := di.PrebuiltExportPath(j.BaseModuleName(), ".dexjar"); dexOutputPath != nil { + j.dexJarFile = dexOutputPath + j.hiddenAPIExtractInformation(ctx, dexOutputPath, outputFile) + } else { // This should never happen as a variant for a prebuilt_apex is only created if the // prebuilt_apex has been configured to export the java library dex file. ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name()) @@ -2952,16 +3002,20 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } - configurationName := j.BaseModuleName() - primary := j.Prebuilt().UsePrebuilt() - // Hidden API CSV generation and dex encoding - dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile, + dexOutputFile = j.hiddenAPIExtractAndEncode(ctx, dexOutputFile, outputFile, proptools.Bool(j.dexProperties.Uncompress_dex)) j.dexJarFile = dexOutputFile } } + + ctx.SetProvider(JavaInfoProvider, JavaInfo{ + HeaderJars: android.PathsIfNonNil(j.combinedClasspathFile), + ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile), + ImplementationJars: android.PathsIfNonNil(j.combinedClasspathFile), + AidlIncludeDirs: j.exportAidlIncludeDirs, + }) } func (j *Import) OutputFiles(tag string) (android.Paths, error) { @@ -2975,8 +3029,6 @@ func (j *Import) OutputFiles(tag string) (android.Paths, error) { var _ android.OutputFileProducer = (*Import)(nil) -var _ Dependency = (*Import)(nil) - func (j *Import) HeaderJars() android.Paths { if j.combinedClasspathFile == nil { return nil @@ -3322,6 +3374,7 @@ func DefaultsFactory() android.Module { &android.ApexProperties{}, &RuntimeResourceOverlayProperties{}, &LintProperties{}, + &appTestHelperAppProperties{}, ) android.InitDefaultsModule(module) diff --git a/java/java_test.go b/java/java_test.go index e7776c35d..0ef4db680 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -127,7 +127,6 @@ func testJavaErrorWithConfig(t *testing.T, pattern string, config android.Config } t.Fatalf("missing expected error %q (0 errors are returned)", pattern) - return ctx, config } @@ -1179,6 +1178,110 @@ func TestIncludeSrcs(t *testing.T) { } } +func TestJavaLint(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + java_library { + name: "foo", + srcs: [ + "a.java", + "b.java", + "c.java", + ], + min_sdk_version: "29", + sdk_version: "system_current", + } + `, map[string][]byte{ + "lint-baseline.xml": nil, + }) + + foo := ctx.ModuleForTests("foo", "android_common") + rule := foo.Rule("lint") + + if !strings.Contains(rule.RuleParams.Command, "--baseline lint-baseline.xml") { + t.Error("did not pass --baseline flag") + } +} + +func TestJavaLintWithoutBaseline(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + java_library { + name: "foo", + srcs: [ + "a.java", + "b.java", + "c.java", + ], + min_sdk_version: "29", + sdk_version: "system_current", + } + `, map[string][]byte{}) + + foo := ctx.ModuleForTests("foo", "android_common") + rule := foo.Rule("lint") + + if strings.Contains(rule.RuleParams.Command, "--baseline") { + t.Error("passed --baseline flag for non existent file") + } +} + +func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) { + config := testConfig( + nil, + ` + java_library { + name: "foo", + srcs: [ + ], + min_sdk_version: "29", + sdk_version: "system_current", + lint: { + baseline_filename: "mybaseline.xml", + }, + } + `, map[string][]byte{ + "build/soong/java/lint_defaults.txt": nil, + "prebuilts/cmdline-tools/tools/bin/lint": nil, + "prebuilts/cmdline-tools/tools/lib/lint-classpath.jar": nil, + "framework/aidl": nil, + "a.java": nil, + "AndroidManifest.xml": nil, + "build/make/target/product/security": nil, + }) + config.TestAllowNonExistentPaths = false + testJavaErrorWithConfig(t, + "source path \"mybaseline.xml\" does not exist", + config, + ) +} + +func TestJavaLintUsesCorrectBpConfig(t *testing.T) { + ctx, _ := testJavaWithFS(t, ` + java_library { + name: "foo", + srcs: [ + "a.java", + "b.java", + "c.java", + ], + min_sdk_version: "29", + sdk_version: "system_current", + lint: { + error_checks: ["SomeCheck"], + baseline_filename: "mybaseline.xml", + }, + } + `, map[string][]byte{ + "mybaseline.xml": nil, + }) + + foo := ctx.ModuleForTests("foo", "android_common") + rule := foo.Rule("lint") + + if !strings.Contains(rule.RuleParams.Command, "--baseline mybaseline.xml") { + t.Error("did not use the correct file for baseline") + } +} + func TestGeneratedSources(t *testing.T) { ctx, _ := testJavaWithFS(t, ` java_library { diff --git a/java/jdeps.go b/java/jdeps.go index 2b5ee7491..0ab2e422b 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -87,8 +87,9 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont dpInfo.Classes = append(dpInfo.Classes, data.Class) } - if dep, ok := module.(Dependency); ok { - dpInfo.Installed_paths = append(dpInfo.Installed_paths, dep.ImplementationJars().Strings()...) + if ctx.ModuleHasProvider(module, JavaInfoProvider) { + dep := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo) + dpInfo.Installed_paths = append(dpInfo.Installed_paths, dep.ImplementationJars.Strings()...) } dpInfo.Classes = android.FirstUniqueStrings(dpInfo.Classes) dpInfo.Installed_paths = android.FirstUniqueStrings(dpInfo.Installed_paths) diff --git a/java/lint.go b/java/lint.go index cd2a904d6..827259573 100644 --- a/java/lint.go +++ b/java/lint.go @@ -19,6 +19,8 @@ import ( "sort" "strings" + "github.com/google/blueprint/proptools" + "android/soong/android" ) @@ -46,6 +48,9 @@ type LintProperties struct { // Modules that provide extra lint checks Extra_check_modules []string + + // Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml". + Baseline_filename *string } } @@ -276,8 +281,9 @@ func (l *linter) lint(ctx android.ModuleContext) { extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag) for _, extraLintCheckModule := range extraLintCheckModules { - if dep, ok := extraLintCheckModule.(Dependency); ok { - l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars()...) + if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo) + l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...) } else { ctx.PropertyErrorf("lint.extra_check_modules", "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule)) @@ -343,6 +349,19 @@ func (l *linter) lint(ctx android.ModuleContext) { cmd.FlagWithArg("--check ", checkOnly) } + if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" { + var lintBaseline android.OptionalPath + if String(l.properties.Lint.Baseline_filename) != "" { + // if manually specified, we require the file to exist + lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename)) + } else { + lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename) + } + if lintBaseline.Valid() { + cmd.FlagWithInput("--baseline ", lintBaseline.Path()) + } + } + cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")") rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String()) diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 1e90149ea..c91b32117 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -106,14 +106,18 @@ func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdk mctx.CreateModule(ImportFactory, &props) } -func createFilegroup(mctx android.LoadHookContext, name string, path string) { - filegroupProps := struct { +func createApiModule(mctx android.LoadHookContext, name string, path string) { + genruleProps := struct { Name *string Srcs []string + Out []string + Cmd *string }{} - filegroupProps.Name = proptools.StringPtr(name) - filegroupProps.Srcs = []string{path} - mctx.CreateModule(android.FileGroupFactory, &filegroupProps) + genruleProps.Name = proptools.StringPtr(name) + genruleProps.Srcs = []string{path} + genruleProps.Out = []string{name} + genruleProps.Cmd = proptools.StringPtr("cp $(in) $(out)") + mctx.CreateModule(genrule.GenRuleFactory, &genruleProps) } func createEmptyFile(mctx android.LoadHookContext, name string) { @@ -205,16 +209,16 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { path string } - // Create filegroups for all (<module>, <scope, <version>) triplets, - // and a "latest" filegroup variant for each (<module>, <scope>) pair - moduleName := func(module, scope, version string) string { + // Create modules for all (<module>, <scope, <version>) triplets, + // and a "latest" module variant for each (<module>, <scope>) pair + apiModuleName := func(module, scope, version string) string { return module + ".api." + scope + "." + version } m := make(map[string]latestApiInfo) for _, f := range files { localPath := strings.TrimPrefix(f, mydir) module, apiver, scope := parseApiFilePath(mctx, localPath) - createFilegroup(mctx, moduleName(module, scope, apiver), localPath) + createApiModule(mctx, apiModuleName(module, scope, apiver), localPath) version, err := strconv.Atoi(apiver) if err != nil { @@ -239,8 +243,8 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { // Sort the keys in order to make build.ninja stable for _, k := range android.SortedStringKeys(m) { info := m[k] - name := moduleName(info.module, info.scope, "latest") - createFilegroup(mctx, name, info.path) + name := apiModuleName(info.module, info.scope, "latest") + createApiModule(mctx, name, info.path) } // Create incompatibilities tracking files for all modules, if we have a "next" api. @@ -258,14 +262,14 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { referencedModule = "android" } - createFilegroup(mctx, moduleName(referencedModule+"-incompatibilities", scope, "latest"), localPath) + createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), localPath) incompatibilities[referencedModule+"."+scope] = true } // Create empty incompatibilities files for remaining modules for _, k := range android.SortedStringKeys(m) { if _, ok := incompatibilities[k]; !ok { - createEmptyFile(mctx, moduleName(m[k].module+"-incompatibilities", m[k].scope, "latest")) + createEmptyFile(mctx, apiModuleName(m[k].module+"-incompatibilities", m[k].scope, "latest")) } } } @@ -279,10 +283,10 @@ func createPrebuiltApiModules(mctx android.LoadHookContext) { } } -// prebuilt_apis is a meta-module that generates filegroup modules for all -// API txt files found under the directory where the Android.bp is located. +// prebuilt_apis is a meta-module that generates modules for all API txt files +// found under the directory where the Android.bp is located. // Specifically, an API file located at ./<ver>/<scope>/api/<module>.txt -// generates a filegroup module named <module>-api.<scope>.<ver>. +// generates a module named <module>-api.<scope>.<ver>. // // It also creates <module>-api.<scope>.latest for the latest <ver>. // diff --git a/java/proto.go b/java/proto.go index dc5519f41..652a4daec 100644 --- a/java/proto.go +++ b/java/proto.go @@ -82,7 +82,7 @@ func protoDeps(ctx android.BottomUpMutatorContext, p *android.ProtoProperties) { case "lite", "": ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-lite") case "full": - if ctx.Host() { + if ctx.Host() || ctx.BazelConversionMode() { ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-full") } else { ctx.PropertyErrorf("proto.type", "full java protos only supported on the host") diff --git a/java/robolectric.go b/java/robolectric.go index c821e5bd3..98bb71040 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -148,10 +148,10 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } for _, dep := range ctx.GetDirectDepsWithTag(libTag) { - m := dep.(Dependency) - r.libs = append(r.libs, m.BaseModuleName()) - if !android.InList(m.BaseModuleName(), config.FrameworkLibraries) { - combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars()...) + m := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) + r.libs = append(r.libs, ctx.OtherModuleName(dep)) + if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) { + combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...) } } @@ -245,10 +245,10 @@ func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFi srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...) for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) { - if dep, ok := m.(Dependency); ok { - depSrcJarArgs, depSrcJarDeps := dep.SrcJarArgs() - srcJarArgs = append(srcJarArgs, depSrcJarArgs...) - srcJarDeps = append(srcJarDeps, depSrcJarDeps...) + if ctx.OtherModuleHasProvider(m, JavaInfoProvider) { + dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo) + srcJarArgs = append(srcJarArgs, dep.SrcJarArgs...) + srcJarDeps = append(srcJarDeps, dep.SrcJarDeps...) } } diff --git a/java/sdk.go b/java/sdk.go index a68abfb51..74d5a81a9 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -566,10 +566,11 @@ func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx and ctx.VisitAllModules(func(module android.Module) { // Collect dex jar paths for the modules listed above. - if j, ok := module.(Dependency); ok { + if ctx.ModuleHasProvider(module, JavaInfoProvider) { + j := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo) name := ctx.ModuleName(module) if i := android.IndexList(name, stubsModules); i != -1 { - stubsJars[i] = j.HeaderJars() + stubsJars[i] = j.HeaderJars } } }) @@ -640,14 +641,26 @@ func createAPIFingerprint(ctx android.SingletonContext) { if ctx.Config().PlatformSdkCodename() == "REL" { cmd.Text("echo REL >").Output(out) - } else if !ctx.Config().AlwaysUsePrebuiltSdks() { - in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil) - if err != nil { - ctx.Errorf("error globbing API files: %s", err) + } else if ctx.Config().FrameworksBaseDirExists(ctx) && !ctx.Config().AlwaysUsePrebuiltSdks() { + cmd.Text("cat") + apiTxtFileModules := []string{ + "frameworks-base-api-current.txt", + "frameworks-base-api-system-current.txt", + "frameworks-base-api-module-lib-current.txt", } - - cmd.Text("cat"). - Inputs(android.PathsForSource(ctx, in)). + count := 0 + ctx.VisitAllModules(func(module android.Module) { + name := ctx.ModuleName(module) + if android.InList(name, apiTxtFileModules) { + cmd.Inputs(android.OutputFilesForModule(ctx, module, "")) + count++ + } + }) + if count != len(apiTxtFileModules) { + ctx.Errorf("Could not find all the expected API modules %v, found %d\n", apiTxtFileModules, count) + return + } + cmd.Input(android.PathForSource(ctx, "frameworks/base/services/api/current.txt")). Text("| md5sum | cut -d' ' -f1 >"). Output(out) } else { diff --git a/java/sdk_library.go b/java/sdk_library.go index 638740f4f..aa96e0dac 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -60,12 +60,12 @@ type scopeDependencyTag struct { apiScope *apiScope // Function for extracting appropriate path information from the dependency. - depInfoExtractor func(paths *scopePaths, dep android.Module) error + depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.Module) error } // Extract tag specific information from the dependency. func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) { - err := tag.depInfoExtractor(paths, dep) + err := tag.depInfoExtractor(paths, ctx, dep) if err != nil { ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error()) } @@ -539,13 +539,14 @@ type scopePaths struct { stubsSrcJar android.OptionalPath } -func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error { - if lib, ok := dep.(Dependency); ok { - paths.stubsHeaderPath = lib.HeaderJars() - paths.stubsImplPath = lib.ImplementationJars() +func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { + if ctx.OtherModuleHasProvider(dep, JavaInfoProvider) { + lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo) + paths.stubsHeaderPath = lib.HeaderJars + paths.stubsImplPath = lib.ImplementationJars return nil } else { - return fmt.Errorf("expected module that implements Dependency, e.g. java_library") + return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") } } @@ -572,7 +573,7 @@ func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsPro paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath()) } -func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error { +func (paths *scopePaths) extractApiInfoFromDep(ctx android.ModuleContext, dep android.Module) error { return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) { paths.extractApiInfoFromApiStubsProvider(provider) }) @@ -582,13 +583,13 @@ func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider Ap paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar()) } -func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error { +func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.Module) error { return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) { paths.extractStubsSourceInfoFromApiStubsProviders(provider) }) } -func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error { +func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.Module) error { return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) { paths.extractApiInfoFromApiStubsProvider(provider) paths.extractStubsSourceInfoFromApiStubsProviders(provider) @@ -951,7 +952,6 @@ type SdkLibrary struct { commonToSdkLibraryAndImport } -var _ Dependency = (*SdkLibrary)(nil) var _ SdkLibraryDependency = (*SdkLibrary)(nil) func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool { diff --git a/java/system_modules.go b/java/system_modules.go index 5cc546d2e..95f71b80f 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -160,8 +160,8 @@ func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleConte var jars android.Paths ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) { - dep, _ := module.(Dependency) - jars = append(jars, dep.HeaderJars()...) + dep, _ := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) + jars = append(jars, dep.HeaderJars...) }) system.headerJars = jars diff --git a/java/testing.go b/java/testing.go index 5fcf84c6b..781106ff2 100644 --- a/java/testing.go +++ b/java/testing.go @@ -18,6 +18,7 @@ import ( "fmt" "reflect" "sort" + "strings" "testing" "android/soong/android" @@ -237,3 +238,11 @@ func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, varia t.Errorf("expected %#q, found %#q", expected, actual) } } + +func CheckHiddenAPIRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) { + actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n")) + expected = strings.TrimSpace(expected) + if actual != expected { + t.Errorf("Expected hiddenapi rule inputs:\n%s\nactual inputs:\n%s", expected, actual) + } +} |