diff options
Diffstat (limited to 'java')
| -rw-r--r-- | java/Android.bp | 2 | ||||
| -rw-r--r-- | java/aar.go | 22 | ||||
| -rw-r--r-- | java/android_manifest.go | 6 | ||||
| -rw-r--r-- | java/androidmk.go | 6 | ||||
| -rwxr-xr-x | java/app.go | 42 | ||||
| -rw-r--r-- | java/app_import.go | 8 | ||||
| -rw-r--r-- | java/base.go | 59 | ||||
| -rw-r--r-- | java/classpath_fragment.go | 151 | ||||
| -rw-r--r-- | java/dexpreopt.go | 2 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars.go | 2 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars_test.go | 3 | ||||
| -rw-r--r-- | java/dexpreopt_config.go | 2 | ||||
| -rw-r--r-- | java/droiddoc.go | 14 | ||||
| -rw-r--r-- | java/hiddenapi.go | 7 | ||||
| -rw-r--r-- | java/hiddenapi_modular.go | 219 | ||||
| -rw-r--r-- | java/hiddenapi_singleton.go | 220 | ||||
| -rw-r--r-- | java/hiddenapi_singleton_test.go | 73 | ||||
| -rw-r--r-- | java/java.go | 37 | ||||
| -rw-r--r-- | java/java_test.go | 8 | ||||
| -rw-r--r-- | java/lint.go | 42 | ||||
| -rw-r--r-- | java/platform_bootclasspath.go | 171 | ||||
| -rw-r--r-- | java/platform_bootclasspath_test.go | 185 | ||||
| -rw-r--r-- | java/prebuilt_apis.go | 10 | ||||
| -rw-r--r-- | java/rro.go | 14 | ||||
| -rw-r--r-- | java/sdk.go | 2 | ||||
| -rw-r--r-- | java/sdk_library.go | 2 | ||||
| -rw-r--r-- | java/testing.go | 37 |
27 files changed, 948 insertions, 398 deletions
diff --git a/java/Android.bp b/java/Android.bp index 8334b85ec..2a4b596ab 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -32,6 +32,7 @@ bootstrap_go_package { "boot_image.go", "boot_jars.go", "builder.go", + "classpath_fragment.go", "device_host_converter.go", "dex.go", "dexpreopt.go", @@ -42,6 +43,7 @@ bootstrap_go_package { "gen.go", "genrule.go", "hiddenapi.go", + "hiddenapi_modular.go", "hiddenapi_singleton.go", "jacoco.go", "java.go", diff --git a/java/aar.go b/java/aar.go index a122a94cb..04727e4b9 100644 --- a/java/aar.go +++ b/java/aar.go @@ -218,7 +218,7 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte linkDeps = append(linkDeps, assetDeps...) // SDK version flags - minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } @@ -609,6 +609,9 @@ type AARImport struct { hideApexVariantFromMake bool aarPath android.Path + + sdkVersion android.SdkSpec + minSdkVersion android.SdkSpec } var _ android.OutputFileProducer = (*AARImport)(nil) @@ -625,23 +628,23 @@ func (a *AARImport) OutputFiles(tag string) (android.Paths, error) { } } -func (a *AARImport) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(a.properties.Sdk_version)) +func (a *AARImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version)) } func (a *AARImport) SystemModules() string { return "" } -func (a *AARImport) MinSdkVersion() android.SdkSpec { +func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { if a.properties.Min_sdk_version != nil { - return android.SdkSpecFrom(*a.properties.Min_sdk_version) + return android.SdkSpecFrom(ctx, *a.properties.Min_sdk_version) } - return a.SdkVersion() + return a.SdkVersion(ctx) } -func (a *AARImport) TargetSdkVersion() android.SdkSpec { - return a.SdkVersion() +func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return a.SdkVersion(ctx) } func (a *AARImport) javaVersion() string { @@ -727,6 +730,9 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } + a.sdkVersion = a.SdkVersion(ctx) + a.minSdkVersion = a.MinSdkVersion(ctx) + a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() aarName := ctx.ModuleName() + ".aar" diff --git a/java/android_manifest.go b/java/android_manifest.go index 8510f30dd..331f941ec 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -51,7 +51,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext if isLibrary { args = append(args, "--library") } else { - minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersion(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } @@ -87,7 +87,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext args = append(args, "--logging-parent", loggingParent) } var deps android.Paths - targetSdkVersion, err := sdkContext.TargetSdkVersion().EffectiveVersionString(ctx) + targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid targetSdkVersion: %s", err) } @@ -96,7 +96,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext deps = append(deps, ApiFingerprintPath(ctx)) } - minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } diff --git a/java/androidmk.go b/java/androidmk.go index 75661a7a5..4e594a2fa 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -106,7 +106,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if len(library.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled) } - entries.SetString("LOCAL_SDK_VERSION", library.SdkVersion().Raw) + entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion.String()) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar) entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile) @@ -205,7 +205,7 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { } entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion()) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String()) entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem()) }, }, @@ -255,7 +255,7 @@ func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags) entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile) entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.SdkVersion().Raw) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String()) }, }, }} diff --git a/java/app.go b/java/app.go index 04406e734..5695022f9 100755 --- a/java/app.go +++ b/java/app.go @@ -213,7 +213,7 @@ func (c Certificate) AndroidMkString() string { func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { a.Module.deps(ctx) - if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion().Specified() { + if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion(ctx).Specified() { ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared") } @@ -222,7 +222,7 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { a.aapt.deps(ctx, sdkDep) } - usesSDK := a.SdkVersion().Specified() && a.SdkVersion().Kind != android.SdkCorePlatform + usesSDK := a.SdkVersion(ctx).Specified() && a.SdkVersion(ctx).Kind != android.SdkCorePlatform if usesSDK && Bool(a.appProperties.Jni_uses_sdk_apis) { ctx.PropertyErrorf("jni_uses_sdk_apis", @@ -279,14 +279,14 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if a.Updatable() { - if !a.SdkVersion().Stable() { - ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion()) + if !a.SdkVersion(ctx).Stable() { + ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion(ctx)) } if String(a.deviceProperties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") } - if minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx); err == nil { + if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil { a.checkJniLibsSdkVersion(ctx, minSdkVersion) android.CheckMinSdkVersion(a, ctx, minSdkVersion) } else { @@ -314,7 +314,7 @@ func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVer // The domain of cc.sdk_version is "current" and <number> // We can rely on android.SdkSpec to convert it to <number> so that "current" is // handled properly regardless of sdk finalization. - jniSdkVersion, err := android.SdkSpecFrom(dep.SdkVersion()).EffectiveVersion(ctx) + jniSdkVersion, err := android.SdkSpecFrom(ctx, dep.SdkVersion()).EffectiveVersion(ctx) if err != nil || minSdkVersion.LessThan(jniSdkVersion) { ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)", dep.SdkVersion(), minSdkVersion, ctx.ModuleName()) @@ -327,9 +327,9 @@ func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVer // Returns true if the native libraries should be stored in the APK uncompressed and the // extractNativeLibs application flag should be set to false in the manifest. func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool { - minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx) + minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx) if err != nil { - ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(), err) + ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(ctx), err) } apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) @@ -381,7 +381,7 @@ func (a *AndroidApp) renameResourcesPackage() bool { func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { usePlatformAPI := proptools.Bool(a.Module.deviceProperties.Platform_apis) - if ctx.Module().(android.SdkContext).SdkVersion().Kind == android.SdkModule { + if ctx.Module().(android.SdkContext).SdkVersion(ctx).Kind == android.SdkModule { usePlatformAPI = true } a.aapt.usesNonSdkApis = usePlatformAPI @@ -724,8 +724,8 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } type appDepsInterface interface { - SdkVersion() android.SdkSpec - MinSdkVersion() android.SdkSpec + SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec + MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec RequiresStableAPIs(ctx android.BaseModuleContext) bool } @@ -738,8 +738,8 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, seenModulePaths := make(map[string]bool) if checkNativeSdkVersion { - checkNativeSdkVersion = app.SdkVersion().Specified() && - app.SdkVersion().Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) + checkNativeSdkVersion = app.SdkVersion(ctx).Specified() && + app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) } ctx.WalkDeps(func(module android.Module, parent android.Module) bool { @@ -829,12 +829,16 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { depsInfo[depName] = info } else { toMinSdkVersion := "(no version)" - if m, ok := to.(interface{ MinSdkVersion() string }); ok { - if v := m.MinSdkVersion(); v != "" { - toMinSdkVersion = v + if m, ok := to.(interface { + MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec + }); ok { + if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() { + toMinSdkVersion = v.ApiLevel.String() } - } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok { - if v := m.MinSdkVersionString(); v != "" { + } else if m, ok := to.(interface{ MinSdkVersion() string }); ok { + // TODO(b/175678607) eliminate the use of MinSdkVersion returning + // string + if v := m.MinSdkVersion(); v != "" { toMinSdkVersion = v } } @@ -848,7 +852,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { return true }) - a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersionString(), depsInfo) + a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depsInfo) } func (a *AndroidApp) Updatable() bool { diff --git a/java/app_import.go b/java/app_import.go index 32cec2309..839051ea8 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -394,12 +394,12 @@ func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ androi return false } -func (a *AndroidAppImport) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom("") +func (a *AndroidAppImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecPrivate } -func (a *AndroidAppImport) MinSdkVersion() android.SdkSpec { - return android.SdkSpecFrom("") +func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecPrivate } var _ android.ApexModule = (*AndroidAppImport)(nil) diff --git a/java/base.go b/java/base.go index 9bc0738e6..19c85cd75 100644 --- a/java/base.go +++ b/java/base.go @@ -370,10 +370,13 @@ type Module struct { modulePaths []string hideApexVariantFromMake bool + + sdkVersion android.SdkSpec + minSdkVersion android.SdkSpec } -func (j *Module) CheckStableSdkVersion() error { - sdkVersion := j.SdkVersion() +func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error { + sdkVersion := j.SdkVersion(ctx) if sdkVersion.Stable() { return nil } @@ -393,7 +396,7 @@ func (j *Module) CheckStableSdkVersion() error { func (j *Module) checkSdkVersions(ctx android.ModuleContext) { if j.RequiresStableAPIs(ctx) { if sc, ok := ctx.Module().(android.SdkContext); ok { - if !sc.SdkVersion().Specified() { + if !sc.SdkVersion(ctx).Specified() { ctx.PropertyErrorf("sdk_version", "sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).") } @@ -418,7 +421,7 @@ func (j *Module) checkSdkVersions(ctx android.ModuleContext) { func (j *Module) checkPlatformAPI(ctx android.ModuleContext) { if sc, ok := ctx.Module().(android.SdkContext); ok { usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis) - sdkVersionSpecified := sc.SdkVersion().Specified() + sdkVersionSpecified := sc.SdkVersion(ctx).Specified() if usePlatformAPI && sdkVersionSpecified { ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.") } else if !usePlatformAPI && !sdkVersionSpecified { @@ -512,30 +515,30 @@ func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool { return false } -func (j *Module) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(j.deviceProperties.Sdk_version)) +func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version)) } func (j *Module) SystemModules() string { return proptools.String(j.deviceProperties.System_modules) } -func (j *Module) MinSdkVersion() android.SdkSpec { +func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { if j.deviceProperties.Min_sdk_version != nil { - return android.SdkSpecFrom(*j.deviceProperties.Min_sdk_version) + return android.SdkSpecFrom(ctx, *j.deviceProperties.Min_sdk_version) } - return j.SdkVersion() + return j.SdkVersion(ctx) } -func (j *Module) TargetSdkVersion() android.SdkSpec { - if j.deviceProperties.Target_sdk_version != nil { - return android.SdkSpecFrom(*j.deviceProperties.Target_sdk_version) - } - return j.SdkVersion() +func (j *Module) MinSdkVersionString() string { + return j.minSdkVersion.Raw } -func (j *Module) MinSdkVersionString() string { - return j.MinSdkVersion().ApiLevel.String() +func (j *Module) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + if j.deviceProperties.Target_sdk_version != nil { + return android.SdkSpecFrom(ctx, *j.deviceProperties.Target_sdk_version) + } + return j.SdkVersion(ctx) } func (j *Module) AvailableFor(what string) bool { @@ -1209,7 +1212,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } // Dex compilation var dexOutputFile android.OutputPath - dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName) if ctx.Failed() { return } @@ -1267,9 +1270,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.linter.srcJars = srcJars j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...) j.linter.classes = j.implementationJarFile - j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion()) - j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion()) - j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion()) + j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion(ctx)) + j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion(ctx)) + j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion(ctx)) j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() { @@ -1471,7 +1474,7 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu // Implements android.ApexModule func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - sdkSpec := j.MinSdkVersion() + sdkSpec := j.MinSdkVersion(ctx) if !sdkSpec.Specified() { return fmt.Errorf("min_sdk_version is not specified") } @@ -1551,10 +1554,10 @@ func (lt sdkLinkType) rank() int { type moduleWithSdkDep interface { android.Module - getSdkLinkType(name string) (ret sdkLinkType, stubs bool) + getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) } -func (m *Module) getSdkLinkType(name string) (ret sdkLinkType, stubs bool) { +func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) { switch name { case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs", "stub-annotations", "private-stub-annotations-jar", @@ -1576,7 +1579,7 @@ func (m *Module) getSdkLinkType(name string) (ret sdkLinkType, stubs bool) { return linkType, true } - ver := m.SdkVersion() + ver := m.SdkVersion(ctx) switch ver.Kind { case android.SdkCore: return javaCore, false @@ -1606,11 +1609,11 @@ func (j *Module) checkSdkLinkType( return } - myLinkType, stubs := j.getSdkLinkType(ctx.ModuleName()) + myLinkType, stubs := j.getSdkLinkType(ctx, ctx.ModuleName()) if stubs { return } - depLinkType, _ := dep.getSdkLinkType(ctx.OtherModuleName(dep)) + depLinkType, _ := dep.getSdkLinkType(ctx, ctx.OtherModuleName(dep)) if myLinkType.rank() < depLinkType.rank() { ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+ @@ -1638,7 +1641,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } - sdkLinkType, _ := j.getSdkLinkType(ctx.ModuleName()) + sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName()) ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) @@ -1656,7 +1659,7 @@ 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())...) + deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go new file mode 100644 index 000000000..d4974600f --- /dev/null +++ b/java/classpath_fragment.go @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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 ( + "fmt" + "strings" + + "android/soong/android" +) + +// Build rules and utilities to generate individual packages/modules/SdkExtensions/proto/classpaths.proto +// config files based on build configuration to embed into /system and /apex on a device. +// +// See `derive_classpath` service that reads the configs at runtime and defines *CLASSPATH variables +// on the device. + +type classpathType int + +const ( + // Matches definition in packages/modules/SdkExtensions/proto/classpaths.proto + BOOTCLASSPATH classpathType = iota + DEX2OATBOOTCLASSPATH + SYSTEMSERVERCLASSPATH +) + +func (c classpathType) String() string { + return [...]string{"BOOTCLASSPATH", "DEX2OATBOOTCLASSPATH", "SYSTEMSERVERCLASSPATH"}[c] +} + +type classpathFragmentProperties struct { +} + +// classpathFragment interface is implemented by a module that contributes jars to a *CLASSPATH +// variables at runtime. +type classpathFragment interface { + android.Module + + classpathFragmentBase() *ClasspathFragmentBase +} + +// ClasspathFragmentBase is meant to be embedded in any module types that implement classpathFragment; +// such modules are expected to call initClasspathFragment(). +type ClasspathFragmentBase struct { + properties classpathFragmentProperties + + outputFilepath android.OutputPath + installDirPath android.InstallPath +} + +func (c *ClasspathFragmentBase) classpathFragmentBase() *ClasspathFragmentBase { + return c +} + +// Initializes ClasspathFragmentBase struct. Must be called by all modules that include ClasspathFragmentBase. +func initClasspathFragment(c classpathFragment) { + base := c.classpathFragmentBase() + c.AddProperties(&base.properties) +} + +// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto +type classpathJar struct { + path string + classpath classpathType + // TODO(satayev): propagate min/max sdk versions for the jars + minSdkVersion int32 + maxSdkVersion int32 +} + +func (c *ClasspathFragmentBase) generateAndroidBuildActions(ctx android.ModuleContext) { + outputFilename := ctx.ModuleName() + ".pb" + c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath + c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths") + + var jars []classpathJar + jars = appendClasspathJar(jars, BOOTCLASSPATH, defaultBootclasspath(ctx)...) + jars = appendClasspathJar(jars, DEX2OATBOOTCLASSPATH, defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps...) + jars = appendClasspathJar(jars, SYSTEMSERVERCLASSPATH, systemServerClasspath(ctx)...) + + generatedJson := android.PathForModuleOut(ctx, outputFilename+".json") + writeClasspathsJson(ctx, generatedJson, jars) + + rule := android.NewRuleBuilder(pctx, ctx) + rule.Command(). + BuiltTool("conv_classpaths_proto"). + Flag("encode"). + Flag("--format=json"). + FlagWithInput("--input=", generatedJson). + FlagWithOutput("--output=", c.outputFilepath) + + rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String()) +} + +func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) { + var content strings.Builder + fmt.Fprintf(&content, "{\n") + fmt.Fprintf(&content, "\"jars\": [\n") + for idx, jar := range jars { + fmt.Fprintf(&content, "{\n") + + fmt.Fprintf(&content, "\"relativePath\": \"%s\",\n", jar.path) + fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath) + + if idx < len(jars)-1 { + fmt.Fprintf(&content, "},\n") + } else { + fmt.Fprintf(&content, "}\n") + } + } + fmt.Fprintf(&content, "]\n") + fmt.Fprintf(&content, "}\n") + android.WriteFileRule(ctx, output, content.String()) +} + +func appendClasspathJar(slice []classpathJar, classpathType classpathType, paths ...string) (result []classpathJar) { + result = append(result, slice...) + for _, path := range paths { + result = append(result, classpathJar{ + path: path, + classpath: classpathType, + }) + } + return +} + +func (c *ClasspathFragmentBase) getAndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{android.AndroidMkEntries{ + Class: "ETC", + OutputFile: android.OptionalPathForPath(c.outputFilepath), + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.SetString("LOCAL_MODULE_PATH", c.installDirPath.ToMakePath().String()) + entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.outputFilepath.Base()) + }, + }, + }} +} diff --git a/java/dexpreopt.go b/java/dexpreopt.go index b4cf012af..3571590db 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -221,7 +221,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr DexLocation: dexLocation, BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath, DexPath: dexJarFile, - ManifestPath: d.manifestFile, + ManifestPath: android.OptionalPathForPath(d.manifestFile), UncompressedDex: d.uncompressedDex, HasApkLibraries: false, PreoptFlags: nil, diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 7137f33ba..e57c3e98d 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -484,7 +484,7 @@ func getBootJar(ctx android.SingletonContext, bootjars android.ConfiguredJarList // Now match the apex part of the boot image configuration. requiredApex := bootjars.Apex(index) - if requiredApex == "platform" { + if requiredApex == "platform" || requiredApex == "system_ext" { if len(apexInfo.InApexes) != 0 { // A platform variant is required but this is for an apex so ignore it. return -1, nil, nil diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go index d78651d90..73f21d12e 100644 --- a/java/dexpreopt_bootjars_test.go +++ b/java/dexpreopt_bootjars_test.go @@ -35,6 +35,7 @@ func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOu name: "bar", srcs: ["b.java"], installable: true, + system_ext_specific: true, } dex_import { @@ -47,7 +48,7 @@ func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOu prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("foo"), - dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar", "platform:baz"), + dexpreopt.FixtureSetBootJars("platform:foo", "system_ext:bar", "platform:baz"), ).RunTestWithBp(t, bp) dexpreoptBootJars := result.SingletonForTests("dex_bootjars") diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index 64b265640..656f5ef71 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -26,7 +26,7 @@ import ( // systemServerClasspath returns the on-device locations of the modules in the system server classpath. It is computed // once the first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same // ctx.Config(). -func systemServerClasspath(ctx android.MakeVarsContext) []string { +func systemServerClasspath(ctx android.PathContext) []string { return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string { global := dexpreopt.GetGlobalConfig(ctx) var systemServerClasspathLocations []string diff --git a/java/droiddoc.go b/java/droiddoc.go index e527d59bc..01c0f16ff 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -261,20 +261,20 @@ func JavadocHostFactory() android.Module { var _ android.OutputFileProducer = (*Javadoc)(nil) -func (j *Javadoc) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(j.properties.Sdk_version)) +func (j *Javadoc) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version)) } func (j *Javadoc) SystemModules() string { return proptools.String(j.properties.System_modules) } -func (j *Javadoc) MinSdkVersion() android.SdkSpec { - return j.SdkVersion() +func (j *Javadoc) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return j.SdkVersion(ctx) } -func (j *Javadoc) TargetSdkVersion() android.SdkSpec { - return j.SdkVersion() +func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return j.SdkVersion(ctx) } func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) { @@ -386,7 +386,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { } case libTag: if dep, ok := module.(SdkLibraryDependency); ok { - deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...) + deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) deps.classpath = append(deps.classpath, dep.HeaderJars...) diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 208ced769..3ecb9772a 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -111,6 +111,13 @@ type hiddenAPIIntf interface { var _ hiddenAPIIntf = (*hiddenAPI)(nil) +// hiddenAPISupportingModule is the interface that is implemented by any module that supports +// contributing to the hidden API processing. +type hiddenAPISupportingModule interface { + android.Module + hiddenAPIIntf +} + // Initialize the hiddenapi structure func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, configurationName string) { // If hiddenapi processing is disabled treat this as inactive. diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go new file mode 100644 index 000000000..7cf082b6a --- /dev/null +++ b/java/hiddenapi_modular.go @@ -0,0 +1,219 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "android/soong/android" +) + +// Contains support for processing hiddenAPI in a modular fashion. + +// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the +// information obtained from annotations within the source code in order to create the complete set +// of flags that should be applied to the dex implementation jars on the bootclasspath. +// +// Each property contains a list of paths. With the exception of the Unsupported_packages the paths +// of each property reference a plain text file that contains a java signature per line. The flags +// for each of those signatures will be updated in a property specific way. +// +// The Unsupported_packages property contains a list of paths, each of which is a plain text file +// with one Java package per line. All members of all classes within that package (but not nested +// packages) will be updated in a property specific way. +type HiddenAPIFlagFileProperties struct { + // Marks each signature in the referenced files as being unsupported. + Unsupported []string `android:"path"` + + // Marks each signature in the referenced files as being unsupported because it has been removed. + // Any conflicts with other flags are ignored. + Removed []string `android:"path"` + + // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R + // and low priority. + Max_target_r_low_priority []string `android:"path"` + + // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q. + Max_target_q []string `android:"path"` + + // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P. + Max_target_p []string `android:"path"` + + // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O + // and low priority. Any conflicts with other flags are ignored. + Max_target_o_low_priority []string `android:"path"` + + // Marks each signature in the referenced files as being blocked. + Blocked []string `android:"path"` + + // Marks each signature in every package in the referenced files as being unsupported. + Unsupported_packages []string `android:"path"` +} + +func (p *HiddenAPIFlagFileProperties) hiddenAPIFlagFileInfo(ctx android.ModuleContext) hiddenAPIFlagFileInfo { + info := hiddenAPIFlagFileInfo{categoryToPaths: map[*hiddenAPIFlagFileCategory]android.Paths{}} + for _, category := range hiddenAPIFlagFileCategories { + paths := android.PathsForModuleSrc(ctx, category.propertyAccessor(p)) + info.categoryToPaths[category] = paths + } + return info +} + +type hiddenAPIFlagFileCategory struct { + // propertyName is the name of the property for this category. + propertyName string + + // propertyAccessor retrieves the value of the property for this category from the set of + // properties. + propertyAccessor func(properties *HiddenAPIFlagFileProperties) []string + + // commandMutator adds the appropriate command line options for this category to the supplied + // command + commandMutator func(command *android.RuleBuilderCommand, path android.Path) +} + +var hiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ + // See HiddenAPIFlagFileProperties.Unsupported + { + propertyName: "unsupported", + propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + return properties.Unsupported + }, + commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { + command.FlagWithInput("--unsupported ", path) + }, + }, + // See HiddenAPIFlagFileProperties.Removed + { + propertyName: "removed", + propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + return properties.Removed + }, + commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { + command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed") + }, + }, + // See HiddenAPIFlagFileProperties.Max_target_r_low_priority + { + propertyName: "max_target_r_low_priority", + propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + return properties.Max_target_r_low_priority + }, + commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { + command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio") + }, + }, + // See HiddenAPIFlagFileProperties.Max_target_q + { + propertyName: "max_target_q", + propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + return properties.Max_target_q + }, + commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { + command.FlagWithInput("--max-target-q ", path) + }, + }, + // See HiddenAPIFlagFileProperties.Max_target_p + { + propertyName: "max_target_p", + propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + return properties.Max_target_p + }, + commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { + command.FlagWithInput("--max-target-p ", path) + }, + }, + // See HiddenAPIFlagFileProperties.Max_target_o_low_priority + { + propertyName: "max_target_o_low_priority", + propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + return properties.Max_target_o_low_priority + }, + commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { + command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio") + }, + }, + // See HiddenAPIFlagFileProperties.Blocked + { + propertyName: "blocked", + propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + return properties.Blocked + }, + commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { + command.FlagWithInput("--blocked ", path) + }, + }, + // See HiddenAPIFlagFileProperties.Unsupported_packages + { + propertyName: "unsupported_packages", + propertyAccessor: func(properties *HiddenAPIFlagFileProperties) []string { + return properties.Unsupported_packages + }, + commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { + command.FlagWithInput("--unsupported ", path).Flag("--packages ") + }, + }, +} + +// hiddenAPIFlagFileInfo contains paths resolved from HiddenAPIFlagFileProperties +type hiddenAPIFlagFileInfo struct { + // categoryToPaths maps from the flag file category to the paths containing information for that + // category. + categoryToPaths map[*hiddenAPIFlagFileCategory]android.Paths +} + +// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the +// flags from all the modules, the stub flags, augmented with some additional configuration files. +// +// baseFlagsPath is the path to the flags file containing all the information from the stubs plus +// an entry for every single member in the dex implementation jars of the individual modules. Every +// signature in any of the other files MUST be included in this file. +// +// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using +// information from the baseFlagsPath as well as from annotations within the source. +// +// augmentationInfo is a struct containing paths to files that augment the information provided by +// the moduleSpecificFlagsPaths. +// ruleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from the +// flags from all the modules, the stub flags, augmented with some additional configuration files. +// +// baseFlagsPath is the path to the flags file containing all the information from the stubs plus +// an entry for every single member in the dex implementation jars of the individual modules. Every +// signature in any of the other files MUST be included in this file. +// +// moduleSpecificFlagsPaths are the paths to the flags files generated by each module using +// information from the baseFlagsPath as well as from annotations within the source. +// +// augmentationInfo is a struct containing paths to files that augment the information provided by +// the moduleSpecificFlagsPaths. +func ruleToGenerateHiddenApiFlags(ctx android.BuilderContext, outputPath android.WritablePath, baseFlagsPath android.Path, moduleSpecificFlagsPaths android.Paths, augmentationInfo hiddenAPIFlagFileInfo) { + tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp") + rule := android.NewRuleBuilder(pctx, ctx) + command := rule.Command(). + BuiltTool("generate_hiddenapi_lists"). + FlagWithInput("--csv ", baseFlagsPath). + Inputs(moduleSpecificFlagsPaths). + FlagWithOutput("--output ", tempPath) + + // Add the options for the different categories of flag files. + for _, category := range hiddenAPIFlagFileCategories { + paths := augmentationInfo.categoryToPaths[category] + for _, path := range paths { + category.commandMutator(command, path) + } + } + + commitChangeForRestat(rule, tempPath, outputPath) + + rule.Build("hiddenAPIFlagsFile", "hiddenapi flags") +} diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 7e9477bfe..ed0b72250 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -15,10 +15,7 @@ package java import ( - "fmt" - "android/soong/android" - "android/soong/genrule" ) func init() { @@ -27,8 +24,6 @@ func init() { func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) { ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) - ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) - ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory) } var PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents) @@ -102,11 +97,15 @@ var hiddenAPISingletonPathsKey = android.NewOnceKey("hiddenAPISingletonPathsKey" // yet been created. func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct { return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} { + // Make the paths relative to the out/soong/hiddenapi directory instead of to the out/soong/ + // directory. This ensures that if they are used as java_resources they do not end up in a + // hiddenapi directory in the resulting APK. + hiddenapiDir := android.PathForOutput(ctx, "hiddenapi") return hiddenAPISingletonPathsStruct{ - flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"), - index: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"), - metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-unsupported.csv"), - stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"), + flags: hiddenapiDir.Join(ctx, "hiddenapi-flags.csv"), + index: hiddenapiDir.Join(ctx, "hiddenapi-index.csv"), + metadata: hiddenapiDir.Join(ctx, "hiddenapi-unsupported.csv"), + stubFlags: hiddenapiDir.Join(ctx, "hiddenapi-stub-flags.txt"), } }).(hiddenAPISingletonPathsStruct) } @@ -116,7 +115,7 @@ func hiddenAPISingletonFactory() android.Singleton { } type hiddenAPISingleton struct { - flags, metadata android.Path + flags android.Path } // hiddenAPI singleton rules @@ -138,30 +137,25 @@ func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" { h.flags = prebuiltFlagsRule(ctx) + prebuiltIndexRule(ctx) return } // These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them. if ctx.Config().FrameworksBaseDirExists(ctx) { h.flags = flagsRule(ctx) - h.metadata = metadataRule(ctx) } else { h.flags = emptyFlagsRule(ctx) } } // Export paths to Make. INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/. -// Both paths are used to call dist-for-goals. func (h *hiddenAPISingleton) MakeVars(ctx android.MakeVarsContext) { if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { return } ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", h.flags.String()) - - if h.metadata != nil { - ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", h.metadata.String()) - } } // stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image @@ -321,63 +315,21 @@ func prebuiltFlagsRule(ctx android.SingletonContext) android.Path { return outputPath } -// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and -// the unsupported API. -func flagsRule(ctx android.SingletonContext) android.Path { - var flagsCSV android.Paths - var combinedRemovedApis android.Path +func prebuiltIndexRule(ctx android.SingletonContext) { + outputPath := hiddenAPISingletonPaths(ctx).index + inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv") - ctx.VisitAllModules(func(module android.Module) { - if h, ok := module.(hiddenAPIIntf); ok { - if csv := h.flagsCSV(); csv != nil { - flagsCSV = append(flagsCSV, csv) - } - } else if g, ok := module.(*genrule.Module); ok { - if ctx.ModuleName(module) == "combined-removed-dex" { - if len(g.GeneratedSourceFiles()) != 1 || combinedRemovedApis != nil { - ctx.Errorf("Expected 1 combined-removed-dex module that generates 1 output file.") - } - combinedRemovedApis = g.GeneratedSourceFiles()[0] - } - } + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: outputPath, + Input: inputPath, }) +} - if combinedRemovedApis == nil { - ctx.Errorf("Failed to find combined-removed-dex.") - } - - rule := android.NewRuleBuilder(pctx, ctx) - +// flagsRule is a placeholder that simply returns the location of the file, the generation of the +// ninja rules is done in generateHiddenAPIBuildActions. +func flagsRule(ctx android.SingletonContext) android.Path { outputPath := hiddenAPISingletonPaths(ctx).flags - tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp") - - stubFlags := hiddenAPISingletonPaths(ctx).stubFlags - - rule.Command(). - BuiltTool("generate_hiddenapi_lists"). - FlagWithInput("--csv ", stubFlags). - Inputs(flagsCSV). - FlagWithInput("--unsupported ", - android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-unsupported.txt")). - FlagWithInput("--unsupported ", combinedRemovedApis).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed"). - FlagWithInput("--max-target-r ", - android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt")).FlagWithArg("--tag ", "lo-prio"). - FlagWithInput("--max-target-q ", - android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-q.txt")). - FlagWithInput("--max-target-p ", - android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-p.txt")). - FlagWithInput("--max-target-o ", android.PathForSource( - ctx, "frameworks/base/boot/hiddenapi/hiddenapi-max-target-o.txt")).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio"). - FlagWithInput("--blocked ", - android.PathForSource(ctx, "frameworks/base/boot/hiddenapi/hiddenapi-force-blocked.txt")). - FlagWithInput("--unsupported ", android.PathForSource( - ctx, "frameworks/base/boot/hiddenapi/hiddenapi-unsupported-packages.txt")).Flag("--packages "). - FlagWithOutput("--output ", tempPath) - - commitChangeForRestat(rule, tempPath, outputPath) - - rule.Build("hiddenAPIFlagsFile", "hiddenapi flags") - return outputPath } @@ -396,34 +348,6 @@ func emptyFlagsRule(ctx android.SingletonContext) android.Path { return outputPath } -// metadataRule creates a rule to build hiddenapi-unsupported.csv out of the metadata.csv files generated for boot image -// modules. -func metadataRule(ctx android.SingletonContext) android.Path { - var metadataCSV android.Paths - - ctx.VisitAllModules(func(module android.Module) { - if h, ok := module.(hiddenAPIIntf); ok { - if csv := h.metadataCSV(); csv != nil { - metadataCSV = append(metadataCSV, csv) - } - } - }) - - rule := android.NewRuleBuilder(pctx, ctx) - - outputPath := hiddenAPISingletonPaths(ctx).metadata - - rule.Command(). - BuiltTool("merge_csv"). - Flag("--key_field signature"). - FlagWithOutput("--output=", outputPath). - Inputs(metadataCSV) - - rule.Build("hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata") - - return outputPath -} - // commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different. It // also marks the rule as restat and marks the tempPath as a temporary file that should not be considered an output of // the rule. @@ -441,105 +365,3 @@ func commitChangeForRestat(rule *android.RuleBuilder, tempPath, outputPath andro Text("fi"). Text(")") } - -type hiddenAPIFlagsProperties struct { - // name of the file into which the flags will be copied. - Filename *string -} - -type hiddenAPIFlags struct { - android.ModuleBase - - properties hiddenAPIFlagsProperties - - outputFilePath android.OutputPath -} - -func (h *hiddenAPIFlags) GenerateAndroidBuildActions(ctx android.ModuleContext) { - filename := String(h.properties.Filename) - - inputPath := hiddenAPISingletonPaths(ctx).flags - h.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath - - // This ensures that outputFilePath has the correct name for others to - // use, as the source file may have a different name. - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Output: h.outputFilePath, - Input: inputPath, - }) -} - -func (h *hiddenAPIFlags) OutputFiles(tag string) (android.Paths, error) { - switch tag { - case "": - return android.Paths{h.outputFilePath}, nil - default: - return nil, fmt.Errorf("unsupported module reference tag %q", tag) - } -} - -// hiddenapi-flags provides access to the hiddenapi-flags.csv file generated during the build. -func hiddenAPIFlagsFactory() android.Module { - module := &hiddenAPIFlags{} - module.AddProperties(&module.properties) - android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) - return module -} - -func hiddenAPIIndexSingletonFactory() android.Singleton { - return &hiddenAPIIndexSingleton{} -} - -type hiddenAPIIndexSingleton struct { - index android.Path -} - -func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonContext) { - // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { - return - } - - if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" { - outputPath := hiddenAPISingletonPaths(ctx).index - inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv") - - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Output: outputPath, - Input: inputPath, - }) - - h.index = outputPath - return - } - - indexes := android.Paths{} - ctx.VisitAllModules(func(module android.Module) { - if h, ok := module.(hiddenAPIIntf); ok { - if h.indexCSV() != nil { - indexes = append(indexes, h.indexCSV()) - } - } - }) - - rule := android.NewRuleBuilder(pctx, ctx) - rule.Command(). - BuiltTool("merge_csv"). - Flag("--key_field signature"). - FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties"). - FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index). - Inputs(indexes) - rule.Build("singleton-merged-hiddenapi-index", "Singleton merged Hidden API index") - - h.index = hiddenAPISingletonPaths(ctx).index -} - -func (h *hiddenAPIIndexSingleton) MakeVars(ctx android.MakeVarsContext) { - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { - return - } - - ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_INDEX", h.index.String()) -} diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index 5c449e506..5ea9a5bca 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -23,12 +23,6 @@ import ( "github.com/google/blueprint/proptools" ) -func fixtureSetBootJarsProductVariable(bootJars ...string) android.FixturePreparer { - return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.BootJars = android.CreateTestConfiguredJarList(bootJars) - }) -} - func fixtureSetPrebuiltHiddenApiDirProductVariable(prebuiltHiddenApiDir *string) android.FixturePreparer { return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir @@ -41,7 +35,7 @@ var hiddenApiFixtureFactory = android.GroupFixturePreparers( func TestHiddenAPISingleton(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, - fixtureSetBootJarsProductVariable("platform:foo"), + FixtureConfigureBootJars("platform:foo"), ).RunTestWithBp(t, ` java_library { name: "foo", @@ -56,61 +50,6 @@ func TestHiddenAPISingleton(t *testing.T) { android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } -func TestHiddenAPIIndexSingleton(t *testing.T) { - result := android.GroupFixturePreparers( - hiddenApiFixtureFactory, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("bar"), - fixtureSetBootJarsProductVariable("platform:foo", "platform:bar"), - ).RunTestWithBp(t, ` - java_library { - name: "foo", - srcs: ["a.java"], - compile_dex: true, - - hiddenapi_additional_annotations: [ - "foo-hiddenapi-annotations", - ], - } - - 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, - } - `) - - hiddenAPIIndex := result.SingletonForTests("hiddenapi_index") - indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index") - CheckHiddenAPIRuleInputs(t, ` -.intermediates/bar/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 := result.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 TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) { expectedErrorMessage := "hiddenapi has determined that the source module \"foo\" should be ignored as it has been" + @@ -119,7 +58,7 @@ func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) android.GroupFixturePreparers( hiddenApiFixtureFactory, - fixtureSetBootJarsProductVariable("platform:foo"), + FixtureConfigureBootJars("platform:foo"), ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)). RunTestWithBp(t, ` java_library { @@ -139,7 +78,7 @@ func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, - fixtureSetBootJarsProductVariable("platform:foo"), + FixtureConfigureBootJars("platform:foo"), ).RunTestWithBp(t, ` java_import { name: "foo", @@ -157,7 +96,7 @@ func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, - fixtureSetBootJarsProductVariable("platform:foo"), + FixtureConfigureBootJars("platform:foo"), ).RunTestWithBp(t, ` java_library { name: "foo", @@ -185,7 +124,7 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, - fixtureSetBootJarsProductVariable("platform:foo"), + FixtureConfigureBootJars("platform:foo"), ).RunTestWithBp(t, ` java_library { name: "foo", @@ -295,7 +234,7 @@ func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { result := android.GroupFixturePreparers( hiddenApiFixtureFactory, - fixtureSetBootJarsProductVariable("platform:foo"), + FixtureConfigureBootJars("platform:foo"), fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir), ).RunTestWithBp(t, ` java_import { diff --git a/java/java.go b/java/java.go index fa7c96eff..ee4f2eb0b 100644 --- a/java/java.go +++ b/java/java.go @@ -356,7 +356,7 @@ func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext an if javaVersion != "" { return normalizeJavaVersion(ctx, javaVersion) } else if ctx.Device() { - return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion()) + return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx)) } else { return JAVA_VERSION_9 } @@ -463,6 +463,9 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { // would the <x> library if <x> was configured as a boot jar. j.initHiddenAPI(ctx, j.ConfigurationName()) + j.sdkVersion = j.SdkVersion(ctx) + j.minSdkVersion = j.MinSdkVersion(ctx) + apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { j.hideApexVariantFromMake = true @@ -1130,33 +1133,28 @@ type Import struct { exportAidlIncludeDirs android.Paths hideApexVariantFromMake bool -} -func (j *Import) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(j.properties.Sdk_version)) + sdkVersion android.SdkSpec + minSdkVersion android.SdkSpec } -func (j *Import) makeSdkVersion() string { - return j.SdkVersion().Raw +func (j *Import) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version)) } func (j *Import) SystemModules() string { return "none" } -func (j *Import) MinSdkVersion() android.SdkSpec { +func (j *Import) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { if j.properties.Min_sdk_version != nil { - return android.SdkSpecFrom(*j.properties.Min_sdk_version) + return android.SdkSpecFrom(ctx, *j.properties.Min_sdk_version) } - return j.SdkVersion() + return j.SdkVersion(ctx) } -func (j *Import) TargetSdkVersion() android.SdkSpec { - return j.SdkVersion() -} - -func (j *Import) MinSdkVersionString() string { - return j.MinSdkVersion().ApiLevel.String() +func (j *Import) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return j.SdkVersion(ctx) } func (j *Import) Prebuilt() *android.Prebuilt { @@ -1192,6 +1190,9 @@ func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { } func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { + j.sdkVersion = j.SdkVersion(ctx) + j.minSdkVersion = j.MinSdkVersion(ctx) + // Initialize the hiddenapi structure. j.initHiddenAPI(ctx, j.BaseModuleName()) @@ -1230,7 +1231,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } else if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: - flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...) + flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) } } @@ -1291,7 +1292,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex var dexOutputFile android.OutputPath - dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName) if ctx.Failed() { return } @@ -1359,7 +1360,7 @@ func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu // Implements android.ApexModule func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - sdkSpec := j.MinSdkVersion() + sdkSpec := j.MinSdkVersion(ctx) if !sdkSpec.Specified() { return fmt.Errorf("min_sdk_version is not specified") } diff --git a/java/java_test.go b/java/java_test.go index fdf757902..052345871 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1261,6 +1261,14 @@ func TestJavaLintUsesCorrectBpConfig(t *testing.T) { if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") { t.Error("did not use the correct file for baseline") } + + if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") { + t.Error("should check NewApi errors") + } + + if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") { + t.Error("should combine NewApi errors with SomeCheck errors") + } } func TestGeneratedSources(t *testing.T) { diff --git a/java/lint.go b/java/lint.go index 30843dc93..aa308e669 100644 --- a/java/lint.go +++ b/java/lint.go @@ -57,24 +57,25 @@ type LintProperties struct { } type linter struct { - name string - manifest android.Path - mergedManifest android.Path - srcs android.Paths - srcJars android.Paths - resources android.Paths - classpath android.Paths - classes android.Path - extraLintCheckJars android.Paths - test bool - library bool - minSdkVersion string - targetSdkVersion string - compileSdkVersion string - javaLanguageLevel string - kotlinLanguageLevel string - outputs lintOutputs - properties LintProperties + name string + manifest android.Path + mergedManifest android.Path + srcs android.Paths + srcJars android.Paths + resources android.Paths + classpath android.Paths + classes android.Path + extraLintCheckJars android.Paths + test bool + library bool + minSdkVersion string + targetSdkVersion string + compileSdkVersion string + javaLanguageLevel string + kotlinLanguageLevel string + outputs lintOutputs + properties LintProperties + extraMainlineLintErrors []string reports android.Paths @@ -246,6 +247,7 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru cmd.FlagWithInput("@", android.PathForSource(ctx, "build/soong/java/lint_defaults.txt")) + cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors) cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks) cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks) cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks) @@ -282,6 +284,10 @@ func (l *linter) lint(ctx android.ModuleContext) { return } + if l.minSdkVersion != l.compileSdkVersion { + l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, "NewApi") + } + extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag) for _, extraLintCheckModule := range extraLintCheckModules { if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) { diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 95d19b96e..cb8ad683b 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -15,6 +15,8 @@ package java import ( + "fmt" + "android/soong/android" "android/soong/dexpreopt" "github.com/google/blueprint" @@ -57,6 +59,7 @@ var _ android.ExcludeFromVisibilityEnforcementTag = platformBootclasspathDepende type platformBootclasspathModule struct { android.ModuleBase + ClasspathFragmentBase properties platformBootclasspathProperties @@ -69,6 +72,15 @@ type platformBootclasspathModule struct { // // Currently only for testing. fragments []android.Module + + // Path to the monolithic hiddenapi-flags.csv file. + hiddenAPIFlagsCSV android.OutputPath + + // Path to the monolithic hiddenapi-index.csv file. + hiddenAPIIndexCSV android.OutputPath + + // Path to the monolithic hiddenapi-unsupported.csv file. + hiddenAPIMetadataCSV android.OutputPath } // ApexVariantReference specifies a particular apex variant of a module. @@ -84,19 +96,49 @@ type ApexVariantReference struct { } type platformBootclasspathProperties struct { - // The names of the bootclasspath_fragment modules that form part of this // platform_bootclasspath. Fragments []ApexVariantReference + + Hidden_api HiddenAPIFlagFileProperties } func platformBootclasspathFactory() android.Module { m := &platformBootclasspathModule{} m.AddProperties(&m.properties) + // TODO(satayev): split systemserver and apex jars into separate configs. + initClasspathFragment(m) android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) return m } +var _ android.OutputFileProducer = (*platformBootclasspathModule)(nil) + +func (b *platformBootclasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) { + entries = append(entries, android.AndroidMkEntries{ + Class: "FAKE", + // Need at least one output file in order for this to take effect. + OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV), + Include: "$(BUILD_PHONY_PACKAGE)", + }) + entries = append(entries, b.classpathFragmentBase().getAndroidMkEntries()...) + return +} + +// Make the hidden API files available from the platform-bootclasspath module. +func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "hiddenapi-flags.csv": + return android.Paths{b.hiddenAPIFlagsCSV}, nil + case "hiddenapi-index.csv": + return android.Paths{b.hiddenAPIIndexCSV}, nil + case "hiddenapi-metadata.csv": + return android.Paths{b.hiddenAPIMetadataCSV}, nil + } + + return nil, fmt.Errorf("unknown tag %s", tag) +} + func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) { if SkipDexpreoptBootJars(ctx) { return @@ -168,7 +210,30 @@ func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex st // error, unless missing dependencies are allowed. The simplest way to handle that is to add a // dependency that will not be satisfied and the default behavior will handle it. if !addedDep { - ctx.AddFarVariationDependencies(variations, tag, name) + // Add dependency on the unprefixed (i.e. source or renamed prebuilt) module which we know does + // not exist. The resulting error message will contain useful information about the available + // variants. + reportMissingVariationDependency(ctx, variations, name) + + // Add dependency on the missing prefixed prebuilt variant too if a module with that name exists + // so that information about its available variants will be reported too. + if ctx.OtherModuleExists(prebuiltName) { + reportMissingVariationDependency(ctx, variations, prebuiltName) + } + } +} + +// reportMissingVariationDependency intentionally adds a dependency on a missing variation in order +// to generate an appropriate error message with information about the available variations. +func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) { + modules := ctx.AddFarVariationDependencies(variations, nil, name) + if len(modules) != 1 { + panic(fmt.Errorf("Internal Error: expected one module, found %d", len(modules))) + return + } + if modules[0] != nil { + panic(fmt.Errorf("Internal Error: expected module to be missing but was found: %q", modules[0])) + return } } @@ -182,6 +247,8 @@ func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, mod } func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + b.classpathFragmentBase().generateAndroidBuildActions(ctx) + ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) { tag := ctx.OtherModuleDependencyTag(module) if tag == platformBootclasspathModuleDepTag { @@ -191,6 +258,8 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo } }) + b.generateHiddenAPIBuildActions(ctx, b.configuredModules) + // Nothing to do if skipping the dexpreopt of boot image jars. if SkipDexpreoptBootJars(ctx) { return @@ -215,3 +284,101 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig { return defaultBootImageConfig(ctx) } + +// generateHiddenAPIBuildActions generates all the hidden API related build rules. +func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module) { + + // Save the paths to the monolithic files for retrieval via OutputFiles(). + b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags + b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index + b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata + + // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance + // optimization that can be used to reduce the incremental build time but as its name suggests it + // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath. + if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} + for _, path := range paths { + ctx.Build(pctx, android.BuildParams{ + Rule: android.Touch, + Output: path, + }) + } + return + } + + hiddenAPISupportingModules := []hiddenAPISupportingModule{} + for _, module := range modules { + if h, ok := module.(hiddenAPISupportingModule); ok { + if h.bootDexJar() == nil { + ctx.ModuleErrorf("module %s does not provide a bootDexJar file", module) + } + if h.flagsCSV() == nil { + ctx.ModuleErrorf("module %s does not provide a flagsCSV file", module) + } + if h.indexCSV() == nil { + ctx.ModuleErrorf("module %s does not provide an indexCSV file", module) + } + if h.metadataCSV() == nil { + ctx.ModuleErrorf("module %s does not provide a metadataCSV file", module) + } + + if ctx.Failed() { + continue + } + + hiddenAPISupportingModules = append(hiddenAPISupportingModules, h) + } else { + ctx.ModuleErrorf("module %s of type %s does not support hidden API processing", module, ctx.OtherModuleType(module)) + } + } + + moduleSpecificFlagsPaths := android.Paths{} + for _, module := range hiddenAPISupportingModules { + moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, module.flagsCSV()) + } + + augmentationInfo := b.properties.Hidden_api.hiddenAPIFlagFileInfo(ctx) + + outputPath := hiddenAPISingletonPaths(ctx).flags + baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags + ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo) + + b.generateHiddenAPIIndexRules(ctx, hiddenAPISupportingModules) + b.generatedHiddenAPIMetadataRules(ctx, hiddenAPISupportingModules) +} + +func (b *platformBootclasspathModule) generateHiddenAPIIndexRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) { + indexes := android.Paths{} + for _, module := range modules { + indexes = append(indexes, module.indexCSV()) + } + + rule := android.NewRuleBuilder(pctx, ctx) + rule.Command(). + BuiltTool("merge_csv"). + Flag("--key_field signature"). + FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties"). + FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index). + Inputs(indexes) + rule.Build("platform-bootclasspath-monolithic-hiddenapi-index", "monolithic hidden API index") +} + +func (b *platformBootclasspathModule) generatedHiddenAPIMetadataRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) { + metadataCSVFiles := android.Paths{} + for _, module := range modules { + metadataCSVFiles = append(metadataCSVFiles, module.metadataCSV()) + } + + rule := android.NewRuleBuilder(pctx, ctx) + + outputPath := hiddenAPISingletonPaths(ctx).metadata + + rule.Command(). + BuiltTool("merge_csv"). + Flag("--key_field signature"). + FlagWithOutput("--output=", outputPath). + Inputs(metadataCSVFiles) + + rule.Build("platform-bootclasspath-monolithic-hiddenapi-metadata", "monolithic hidden API metadata") +} diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go index ebbe3a5ee..e51b0493a 100644 --- a/java/platform_bootclasspath_test.go +++ b/java/platform_bootclasspath_test.go @@ -31,7 +31,7 @@ var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers( func TestPlatformBootclasspath(t *testing.T) { preparer := android.GroupFixturePreparers( prepareForTestWithPlatformBootclasspath, - dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"), + FixtureConfigureBootJars("platform:foo", "platform:bar"), android.FixtureWithRootAndroidBp(` platform_bootclasspath { name: "platform-bootclasspath", @@ -131,3 +131,186 @@ func TestPlatformBootclasspath(t *testing.T) { }) }) } + +func TestPlatformBootclasspathVariant(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestWithPlatformBootclasspath, + android.FixtureWithRootAndroidBp(` + platform_bootclasspath { + name: "platform-bootclasspath", + } + `), + ).RunTest(t) + + variants := result.ModuleVariantsForTests("platform-bootclasspath") + android.AssertIntEquals(t, "expect 1 variant", 1, len(variants)) +} + +func TestPlatformBootclasspath_ClasspathFragmentPaths(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestWithPlatformBootclasspath, + android.FixtureWithRootAndroidBp(` + platform_bootclasspath { + name: "platform-bootclasspath", + } + `), + ).RunTest(t) + + p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) + android.AssertStringEquals(t, "output filepath", p.Name()+".pb", p.ClasspathFragmentBase.outputFilepath.Base()) + android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath) +} + +func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) { + preparer := android.GroupFixturePreparers( + prepareForTestWithPlatformBootclasspath, + android.FixtureWithRootAndroidBp(` + platform_bootclasspath { + name: "platform-bootclasspath", + } + `), + ) + + t.Run("AndroidMkEntries", func(t *testing.T) { + result := preparer.RunTest(t) + + p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) + + entries := android.AndroidMkEntriesForTest(t, result.TestContext, p) + android.AssertIntEquals(t, "AndroidMkEntries count", 2, len(entries)) + }) + + t.Run("hiddenapi-flags-entry", func(t *testing.T) { + result := preparer.RunTest(t) + + p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) + + entries := android.AndroidMkEntriesForTest(t, result.TestContext, p) + got := entries[0].OutputFile + android.AssertBoolEquals(t, "valid output path", true, got.Valid()) + android.AssertSame(t, "output filepath", p.hiddenAPIFlagsCSV, got.Path()) + }) + + t.Run("classpath-fragment-entry", func(t *testing.T) { + result := preparer.RunTest(t) + + want := map[string][]string{ + "LOCAL_MODULE": {"platform-bootclasspath"}, + "LOCAL_MODULE_CLASS": {"ETC"}, + "LOCAL_INSTALLED_MODULE_STEM": {"platform-bootclasspath.pb"}, + // Output and Install paths are tested separately in TestPlatformBootclasspath_ClasspathFragmentPaths + } + + p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) + + entries := android.AndroidMkEntriesForTest(t, result.TestContext, p) + got := entries[1] + for k, expectedValue := range want { + if value, ok := got.EntryMap[k]; ok { + android.AssertDeepEquals(t, k, expectedValue, value) + } else { + t.Errorf("No %s defined, saw %q", k, got.EntryMap) + } + } + }) +} + +func TestPlatformBootclasspath_Dist(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestWithPlatformBootclasspath, + FixtureConfigureBootJars("platform:foo", "platform:bar"), + android.PrepareForTestWithAndroidMk, + android.FixtureWithRootAndroidBp(` + platform_bootclasspath { + name: "platform-bootclasspath", + dists: [ + { + targets: ["droidcore"], + tag: "hiddenapi-flags.csv", + }, + ], + } + + java_library { + name: "bar", + srcs: ["a.java"], + system_modules: "none", + sdk_version: "none", + compile_dex: true, + } + + java_library { + name: "foo", + srcs: ["a.java"], + system_modules: "none", + sdk_version: "none", + compile_dex: true, + } + `), + ).RunTest(t) + + platformBootclasspath := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) + entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath) + goals := entries[0].GetDistForGoals(platformBootclasspath) + android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0]) + android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[1])) +} + +func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) { + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("bar"), + FixtureConfigureBootJars("platform:foo", "platform:bar"), + ).RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + + hiddenapi_additional_annotations: [ + "foo-hiddenapi-annotations", + ], + } + + 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, + } + + platform_bootclasspath { + name: "myplatform-bootclasspath", + } + `) + + platformBootclasspath := result.ModuleForTests("myplatform-bootclasspath", "android_common") + indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index") + CheckHiddenAPIRuleInputs(t, ` +.intermediates/bar/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 := result.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) +} diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 8a442b5ff..c33e6c229 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -253,14 +253,8 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { files := getPrebuiltFilesInSubdir(mctx, nextApiDir, "api/*incompatibilities.txt") for _, f := range files { localPath := strings.TrimPrefix(f, mydir) - module, _, scope := parseApiFilePath(mctx, localPath) - - // Figure out which module is referenced by this file. Special case for "android". - referencedModule := strings.TrimSuffix(module, "incompatibilities") - referencedModule = strings.TrimSuffix(referencedModule, "-") - if referencedModule == "" { - referencedModule = "android" - } + filename, _, scope := parseApiFilePath(mctx, localPath) + referencedModule := strings.TrimSuffix(filename, "-incompatibilities") createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), localPath) diff --git a/java/rro.go b/java/rro.go index 4ae0014db..2e58c042f 100644 --- a/java/rro.go +++ b/java/rro.go @@ -141,23 +141,23 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile) } -func (r *RuntimeResourceOverlay) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(r.properties.Sdk_version)) +func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(r.properties.Sdk_version)) } func (r *RuntimeResourceOverlay) SystemModules() string { return "" } -func (r *RuntimeResourceOverlay) MinSdkVersion() android.SdkSpec { +func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { if r.properties.Min_sdk_version != nil { - return android.SdkSpecFrom(*r.properties.Min_sdk_version) + return android.SdkSpecFrom(ctx, *r.properties.Min_sdk_version) } - return r.SdkVersion() + return r.SdkVersion(ctx) } -func (r *RuntimeResourceOverlay) TargetSdkVersion() android.SdkSpec { - return r.SdkVersion() +func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return r.SdkVersion(ctx) } func (r *RuntimeResourceOverlay) Certificate() Certificate { diff --git a/java/sdk.go b/java/sdk.go index f324b7661..d6e20a78f 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -61,7 +61,7 @@ func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpe } func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep { - sdkVersion := sdkContext.SdkVersion() + sdkVersion := sdkContext.SdkVersion(ctx) if !sdkVersion.Valid() { ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.Raw) return sdkDep{} diff --git a/java/sdk_library.go b/java/sdk_library.go index 96135c3d4..e5ee39705 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1512,7 +1512,7 @@ func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion andr // force override sdk_version to module_current so that the closest possible API // surface could be found in selectHeaderJarsForSdkVersion if module.defaultsToStubs() && !sdkVersion.Specified() { - sdkVersion = android.SdkSpecFrom("module_current") + sdkVersion = android.SdkSpecFrom(ctx, "module_current") } // Only provide access to the implementation library if it is actually built. diff --git a/java/testing.go b/java/testing.go index 6ebc747db..aee0710c4 100644 --- a/java/testing.go +++ b/java/testing.go @@ -178,6 +178,43 @@ func prebuiltApisFilesForLibs(apiLevels []string, sdkLibs []string) map[string][ return fs } +// FixtureConfigureBootJars configures the boot jars in both the dexpreopt.GlobalConfig and +// Config.productVariables structs. As a side effect that enables dexpreopt. +func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer { + artBootJars := []string{} + for _, j := range bootJars { + artApex := false + for _, artApexName := range artApexNames { + if strings.HasPrefix(j, artApexName+":") { + artApex = true + break + } + } + if artApex { + artBootJars = append(artBootJars, j) + } + } + return android.GroupFixturePreparers( + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BootJars = android.CreateTestConfiguredJarList(bootJars) + }), + dexpreopt.FixtureSetBootJars(bootJars...), + dexpreopt.FixtureSetArtBootJars(artBootJars...), + ) +} + +// FixtureConfigureUpdatableBootJars configures the updatable boot jars in both the +// dexpreopt.GlobalConfig and Config.productVariables structs. As a side effect that enables +// dexpreopt. +func FixtureConfigureUpdatableBootJars(bootJars ...string) android.FixturePreparer { + return android.GroupFixturePreparers( + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars) + }), + dexpreopt.FixtureSetUpdatableBootJars(bootJars...), + ) +} + // registerRequiredBuildComponentsForTest registers the build components used by // PrepareForTestWithJavaDefaultModules. // |