// Copyright 2015 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package java // This file contains the module types for compiling Java for Android, and converts the properties // into the flags and filenames necessary to pass to the Module. The final creation of the rules // is handled in builder.go import ( "fmt" "path/filepath" "strings" "android/soong/bazel" "android/soong/bazel/cquery" "android/soong/remoteexec" "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" "android/soong/cc" "android/soong/dexpreopt" "android/soong/java/config" "android/soong/tradefed" ) func init() { registerJavaBuildComponents(android.InitRegistrationContext) RegisterJavaSdkMemberTypes() } func registerJavaBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("java_defaults", DefaultsFactory) ctx.RegisterModuleType("java_library", LibraryFactory) ctx.RegisterModuleType("java_library_static", LibraryStaticFactory) ctx.RegisterModuleType("java_library_host", LibraryHostFactory) ctx.RegisterModuleType("java_binary", BinaryFactory) ctx.RegisterModuleType("java_binary_host", BinaryHostFactory) ctx.RegisterModuleType("java_test", TestFactory) ctx.RegisterModuleType("java_test_helper_library", TestHelperLibraryFactory) ctx.RegisterModuleType("java_test_host", TestHostFactory) ctx.RegisterModuleType("java_test_import", JavaTestImportFactory) ctx.RegisterModuleType("java_import", ImportFactory) ctx.RegisterModuleType("java_import_host", ImportFactoryHost) ctx.RegisterModuleType("java_device_for_host", DeviceForHostFactory) ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory) ctx.RegisterModuleType("dex_import", DexImportFactory) ctx.RegisterModuleType("java_api_library", ApiLibraryFactory) ctx.RegisterModuleType("java_api_contribution", ApiContributionFactory) // This mutator registers dependencies on dex2oat for modules that should be // dexpreopted. This is done late when the final variants have been // established, to not get the dependencies split into the wrong variants and // to support the checks in dexpreoptDisabled(). ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel() // needs access to ApexInfoProvider which is available after variant creation ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel() }) ctx.RegisterSingletonType("logtags", LogtagsSingleton) ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory) } func RegisterJavaSdkMemberTypes() { // Register sdk member types. android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType) android.RegisterSdkMemberType(javaLibsSdkMemberType) android.RegisterSdkMemberType(javaBootLibsSdkMemberType) android.RegisterSdkMemberType(javaSystemserverLibsSdkMemberType) android.RegisterSdkMemberType(javaTestSdkMemberType) } var ( // Supports adding java header libraries to module_exports and sdk. javaHeaderLibsSdkMemberType = &librarySdkMemberType{ android.SdkMemberTypeBase{ PropertyName: "java_header_libs", SupportsSdk: true, }, func(_ android.SdkMemberContext, j *Library) android.Path { headerJars := j.HeaderJars() if len(headerJars) != 1 { panic(fmt.Errorf("there must be only one header jar from %q", j.Name())) } return headerJars[0] }, sdkSnapshotFilePathForJar, copyEverythingToSnapshot, } // 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] } // Supports adding java implementation libraries to module_exports but not sdk. javaLibsSdkMemberType = &librarySdkMemberType{ android.SdkMemberTypeBase{ PropertyName: "java_libs", }, exportImplementationClassesJar, sdkSnapshotFilePathForJar, copyEverythingToSnapshot, } snapshotRequiresImplementationJar = func(ctx android.SdkMemberContext) bool { // In the S build the build will break if updatable-media does not provide a full implementation // jar. That issue was fixed in Tiramisu by b/229932396. if ctx.IsTargetBuildBeforeTiramisu() && ctx.Name() == "updatable-media" { return true } return false } // Supports adding java boot libraries to module_exports and sdk. // // The build has some implicit dependencies (via the boot jars configuration) on a number of // modules, e.g. core-oj, apache-xml, that are part of the java boot class path and which are // provided by mainline modules (e.g. art, conscrypt, runtime-i18n) but which are not otherwise // used outside those mainline modules. // // As they are not needed outside the mainline modules adding them to the sdk/module-exports as // either java_libs, or java_header_libs would end up exporting more information than was strictly // necessary. The java_boot_libs property to allow those modules to be exported as part of the // sdk/module_exports without exposing any unnecessary information. javaBootLibsSdkMemberType = &librarySdkMemberType{ android.SdkMemberTypeBase{ PropertyName: "java_boot_libs", SupportsSdk: true, }, func(ctx android.SdkMemberContext, j *Library) android.Path { if snapshotRequiresImplementationJar(ctx) { return exportImplementationClassesJar(ctx, j) } // 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(ctx android.SdkMemberContext, osPrefix, name string) string { if snapshotRequiresImplementationJar(ctx) { return sdkSnapshotFilePathForJar(ctx, osPrefix, name) } // 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) }, onlyCopyJarToSnapshot, } // Supports adding java systemserver libraries to module_exports and sdk. // // The build has some implicit dependencies (via the systemserver jars configuration) on a number // of modules that are part of the java systemserver classpath and which are provided by mainline // modules but which are not otherwise used outside those mainline modules. // // As they are not needed outside the mainline modules adding them to the sdk/module-exports as // either java_libs, or java_header_libs would end up exporting more information than was strictly // necessary. The java_systemserver_libs property to allow those modules to be exported as part of // the sdk/module_exports without exposing any unnecessary information. javaSystemserverLibsSdkMemberType = &librarySdkMemberType{ android.SdkMemberTypeBase{ PropertyName: "java_systemserver_libs", SupportsSdk: true, // This was only added in Tiramisu. SupportedBuildReleaseSpecification: "Tiramisu+", }, func(ctx android.SdkMemberContext, j *Library) android.Path { // Java systemserver libs are only provided in the SDK to provide access to their dex // implementation jar for use by dexpreopting. They do not need to provide an actual // implementation jar but the java_import will need a file that exists so just copy an empty // file. Any attempt to use that file as a jar will cause a build error. return ctx.SnapshotBuilder().EmptyFile() }, func(_ android.SdkMemberContext, 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_systemserver_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix) }, onlyCopyJarToSnapshot, } // Supports adding java test libraries to module_exports but not sdk. javaTestSdkMemberType = &testSdkMemberType{ SdkMemberTypeBase: android.SdkMemberTypeBase{ PropertyName: "java_tests", }, } // Rule for generating device binary default wrapper deviceBinaryWrapper = pctx.StaticRule("deviceBinaryWrapper", blueprint.RuleParams{ Command: `echo -e '#!/system/bin/sh\n` + `export CLASSPATH=/system/framework/$jar_name\n` + `exec app_process /$partition/bin $main_class "$$@"'> ${out}`, Description: "Generating device binary wrapper ${jar_name}", }, "jar_name", "partition", "main_class") ) // 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 // set of header jars for all transitive libs deps TransitiveLibsHeaderJars *android.DepSet // set of header jars for all transitive static libs deps TransitiveStaticLibsHeaderJars *android.DepSet // 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{}) // SyspropPublicStubInfo contains info about the sysprop public stub library that corresponds to // the sysprop implementation library. type SyspropPublicStubInfo struct { // JavaInfo is the JavaInfoProvider of the sysprop public stub library that corresponds to // the sysprop implementation library. JavaInfo JavaInfo } var SyspropPublicStubInfoProvider = blueprint.NewProvider(SyspropPublicStubInfo{}) // Methods that need to be implemented for a module that is added to apex java_libs property. type ApexDependency interface { HeaderJars() android.Paths ImplementationAndResourcesJars() android.Paths } // Provides build path and install path to DEX jars. type UsesLibraryDependency interface { DexJarBuildPath() OptionalDexJarPath DexJarInstallPath() android.Path ClassLoaderContexts() dexpreopt.ClassLoaderContextMap } // Provides transitive Proguard flag files to downstream DEX jars. type LibraryDependency interface { ExportedProguardFlagFiles() android.Paths } // TODO(jungjw): Move this to kythe.go once it's created. type xref interface { XrefJavaFiles() android.Paths } func (j *Module) XrefJavaFiles() android.Paths { return j.kytheFiles } type dependencyTag struct { blueprint.BaseDependencyTag name string // True if the dependency is relinked at runtime. runtimeLinked bool // True if the dependency is a toolchain, for example an annotation processor. toolchain bool } // installDependencyTag is a dependency tag that is annotated to cause the installed files of the // dependency to be installed when the parent module is installed. type installDependencyTag struct { blueprint.BaseDependencyTag android.InstallAlwaysNeededDependencyTag name string } func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation { if d.runtimeLinked { return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency} } else if d.toolchain { return []android.LicenseAnnotation{android.LicenseAnnotationToolchain} } return nil } var _ android.LicenseAnnotationsDependencyTag = dependencyTag{} type usesLibraryDependencyTag struct { dependencyTag sdkVersion int // SDK version in which the library appared as a standalone library. optional bool // If the dependency is optional or required. } func makeUsesLibraryDependencyTag(sdkVersion int, optional bool) usesLibraryDependencyTag { return usesLibraryDependencyTag{ dependencyTag: dependencyTag{ name: fmt.Sprintf("uses-library-%d", sdkVersion), runtimeLinked: true, }, sdkVersion: sdkVersion, optional: optional, } } func IsJniDepTag(depTag blueprint.DependencyTag) bool { return depTag == jniLibTag } var ( dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} staticLibTag = dependencyTag{name: "staticlib"} libTag = dependencyTag{name: "javalib", runtimeLinked: true} sdkLibTag = dependencyTag{name: "sdklib", runtimeLinked: true} java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true} pluginTag = dependencyTag{name: "plugin", toolchain: true} errorpronePluginTag = dependencyTag{name: "errorprone-plugin", toolchain: true} exportedPluginTag = dependencyTag{name: "exported-plugin", toolchain: true} bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true} systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true} frameworkResTag = dependencyTag{name: "framework-res"} kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib", runtimeLinked: true} kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations", runtimeLinked: true} kotlinPluginTag = dependencyTag{name: "kotlin-plugin", toolchain: true} proguardRaiseTag = dependencyTag{name: "proguard-raise"} certificateTag = dependencyTag{name: "certificate"} instrumentationForTag = dependencyTag{name: "instrumentation_for"} extraLintCheckTag = dependencyTag{name: "extra-lint-check", toolchain: true} jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true} r8LibraryJarTag = dependencyTag{name: "r8-libraryjar", runtimeLinked: true} syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"} javaApiContributionTag = dependencyTag{name: "java-api-contribution"} depApiSrcsTag = dependencyTag{name: "dep-api-srcs"} jniInstallTag = installDependencyTag{name: "jni install"} binaryInstallTag = installDependencyTag{name: "binary install"} usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false) usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true) usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true) usesLibCompat29ReqTag = makeUsesLibraryDependencyTag(29, false) usesLibCompat30OptTag = makeUsesLibraryDependencyTag(30, true) ) func IsLibDepTag(depTag blueprint.DependencyTag) bool { return depTag == libTag || depTag == sdkLibTag } func IsStaticLibDepTag(depTag blueprint.DependencyTag) bool { return depTag == staticLibTag } type sdkDep struct { useModule, useFiles, invalidVersion bool // The modules that will be added to the bootclasspath when targeting 1.8 or lower bootclasspath []string // The default system modules to use. Will be an empty string if no system // modules are to be used. systemModules string // The modules that will be added to the classpath regardless of the Java language level targeted classpath []string // The modules that will be added ot the classpath when targeting 1.9 or higher // (normally these will be on the bootclasspath when targeting 1.8 or lower) java9Classpath []string frameworkResModule string jars android.Paths aidl android.OptionalPath noStandardLibs, noFrameworksLibs bool } func (s sdkDep) hasStandardLibs() bool { return !s.noStandardLibs } func (s sdkDep) hasFrameworkLibs() bool { return !s.noStandardLibs && !s.noFrameworksLibs } type jniLib struct { name string path android.Path target android.Target coverageFile android.OptionalPath unstrippedFile android.Path partition string } func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext android.SdkContext, d dexer) { sdkDep := decodeSdkDep(ctx, sdkContext) if sdkDep.useModule { ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...) if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { ctx.AddVariationDependencies(nil, proguardRaiseTag, android.JavaApiLibraryNames(ctx.Config(), config.LegacyCorePlatformBootclasspathLibraries)..., ) } if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() { ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...) } } if sdkDep.systemModules != "" { ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) } } type deps struct { // bootClasspath is the list of jars that form the boot classpath (generally the java.* and // android.* classes) for tools that still use it. javac targeting 1.9 or higher uses // systemModules and java9Classpath instead. bootClasspath classpath // classpath is the list of jars that form the classpath for javac and kotlinc rules. It // contains header jars for all static and non-static dependencies. classpath classpath // dexClasspath is the list of jars that form the classpath for d8 and r8 rules. It contains // header jars for all non-static dependencies. Static dependencies have already been // combined into the program jar. dexClasspath classpath // java9Classpath is the list of jars that will be added to the classpath when targeting // 1.9 or higher. It generally contains the android.* classes, while the java.* classes // are provided by systemModules. java9Classpath classpath processorPath classpath errorProneProcessorPath classpath processorClasses []string staticJars android.Paths staticHeaderJars android.Paths staticResourceJars android.Paths aidlIncludeDirs android.Paths srcs android.Paths srcJars android.Paths systemModules *systemModules aidlPreprocess android.OptionalPath kotlinStdlib android.Paths kotlinAnnotations android.Paths kotlinPlugins android.Paths disableTurbine bool } func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) { for _, f := range dep.Srcs() { if f.Ext() != ".jar" { ctx.ModuleErrorf("genrule %q must generate files ending with .jar to be used as a libs or static_libs dependency", ctx.OtherModuleName(dep.(blueprint.Module))) } } } func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext android.SdkContext) javaVersion { if javaVersion != "" { return normalizeJavaVersion(ctx, javaVersion) } else if ctx.Device() { return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx)) } else { return JAVA_VERSION_17 } } // Java version for stubs generation func getStubsJavaVersion() javaVersion { return JAVA_VERSION_8 } type javaVersion int const ( JAVA_VERSION_UNSUPPORTED = 0 JAVA_VERSION_6 = 6 JAVA_VERSION_7 = 7 JAVA_VERSION_8 = 8 JAVA_VERSION_9 = 9 JAVA_VERSION_11 = 11 JAVA_VERSION_17 = 17 ) func (v javaVersion) String() string { switch v { case JAVA_VERSION_6: return "1.6" case JAVA_VERSION_7: return "1.7" case JAVA_VERSION_8: return "1.8" case JAVA_VERSION_9: return "1.9" case JAVA_VERSION_11: return "11" case JAVA_VERSION_17: return "17" default: return "unsupported" } } func (v javaVersion) StringForKotlinc() string { // $ ./external/kotlinc/bin/kotlinc -jvm-target foo // error: unknown JVM target version: foo // Supported versions: 1.6, 1.8, 9, 10, 11, 12, 13, 14, 15, 16, 17 switch v { case JAVA_VERSION_7: return "1.6" case JAVA_VERSION_9: return "9" default: return v.String() } } // Returns true if javac targeting this version uses system modules instead of a bootclasspath. func (v javaVersion) usesJavaModules() bool { return v >= 9 } func normalizeJavaVersion(ctx android.BaseModuleContext, javaVersion string) javaVersion { switch javaVersion { case "1.6", "6": return JAVA_VERSION_6 case "1.7", "7": return JAVA_VERSION_7 case "1.8", "8": return JAVA_VERSION_8 case "1.9", "9": return JAVA_VERSION_9 case "11": return JAVA_VERSION_11 case "17": return JAVA_VERSION_17 case "10", "12", "13", "14", "15", "16": ctx.PropertyErrorf("java_version", "Java language level %s is not supported", javaVersion) return JAVA_VERSION_UNSUPPORTED default: ctx.PropertyErrorf("java_version", "Unrecognized Java language level") return JAVA_VERSION_UNSUPPORTED } } // // Java libraries (.jar file) // type Library struct { Module exportedProguardFlagFiles android.Paths InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths) } var _ LibraryDependency = (*Library)(nil) func (j *Library) ExportedProguardFlagFiles() android.Paths { return j.exportedProguardFlagFiles } var _ android.ApexModule = (*Library)(nil) // Provides access to the list of permitted packages from apex boot jars. type PermittedPackagesForUpdatableBootJars interface { PermittedPackagesForUpdatableBootJars() []string } var _ PermittedPackagesForUpdatableBootJars = (*Library)(nil) func (j *Library) PermittedPackagesForUpdatableBootJars() []string { return j.properties.Permitted_packages } func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool { // Store uncompressed (and aligned) any dex files from jars in APEXes. if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() { return true } // Store uncompressed (and do not strip) dex files from boot class path jars. if inList(ctx.ModuleName(), ctx.Config().BootJars()) { return true } // Store uncompressed dex files that are preopted on /system. if !dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !dexpreopter.odexOnSystemOther(ctx, dexpreopter.installPath)) { return true } if ctx.Config().UncompressPrivAppDex() && inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules()) { return true } return false } // Sets `dexer.dexProperties.Uncompress_dex` to the proper value. func setUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter, dexer *dexer) { if dexer.dexProperties.Uncompress_dex == nil { // If the value was not force-set by the user, use reasonable default based on the module. dexer.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, dexpreopter)) } } func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.provideHiddenAPIPropertyInfo(ctx) j.sdkVersion = j.SdkVersion(ctx) j.minSdkVersion = j.MinSdkVersion(ctx) j.maxSdkVersion = j.MaxSdkVersion(ctx) apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { j.hideApexVariantFromMake = true } j.checkSdkVersions(ctx) if ctx.Device() { j.dexpreopter.installPath = j.dexpreopter.getInstallPath( ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")) j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary setUncompressDex(ctx, &j.dexpreopter, &j.dexer) j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex j.classLoaderContexts = j.usesLibrary.classLoaderContextForUsesLibDeps(ctx) } j.compile(ctx, nil) // Collect the module directory for IDE info in java/jdeps.go. j.modulePaths = append(j.modulePaths, ctx.ModuleDir()) exclusivelyForApex := !apexInfo.IsForPlatform() if (Bool(j.properties.Installable) || ctx.Host()) && !exclusivelyForApex { var extraInstallDeps android.Paths if j.InstallMixin != nil { extraInstallDeps = j.InstallMixin(ctx, j.outputFile) } hostDexNeeded := Bool(j.deviceProperties.Hostdex) && !ctx.Host() if hostDexNeeded { j.hostdexInstallFile = ctx.InstallFile( android.PathForHostDexInstall(ctx, "framework"), j.Stem()+"-hostdex.jar", j.outputFile) } var installDir android.InstallPath if ctx.InstallInTestcases() { var archDir string if !ctx.Host() { archDir = ctx.DeviceConfig().DeviceArch() } installDir = android.PathForModuleInstall(ctx, ctx.ModuleName(), archDir) } else { installDir = android.PathForModuleInstall(ctx, "framework") } j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...) } j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles, android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)...) ctx.VisitDirectDeps(func(m android.Module) { if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag { j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...) } }) j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles) } func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { j.deps(ctx) j.usesLibrary.deps(ctx, false) } const ( aidlIncludeDir = "aidl" javaDir = "java" jarFileSuffix = ".jar" testConfigSuffix = "-AndroidTest.xml" ) // path to the jar file of a java library. Relative to / func sdkSnapshotFilePathForJar(_ android.SdkMemberContext, osPrefix, name string) string { return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix) } func sdkSnapshotFilePathForMember(osPrefix, name string, suffix string) string { return filepath.Join(javaDir, osPrefix, name+suffix) } type librarySdkMemberType struct { android.SdkMemberTypeBase // Function to retrieve the appropriate output jar (implementation or header) from // the library. jarToExportGetter func(ctx android.SdkMemberContext, j *Library) android.Path // Function to compute the snapshot relative path to which the named library's // jar should be copied. snapshotPathGetter func(ctx android.SdkMemberContext, osPrefix, name string) string // True if only the jar should be copied to the snapshot, false if the jar plus any additional // files like aidl files should also be copied. onlyCopyJarToSnapshot bool } const ( onlyCopyJarToSnapshot = true copyEverythingToSnapshot = false ) func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) { ctx.AddVariationDependencies(nil, dependencyTag, names...) } func (mt *librarySdkMemberType) IsInstance(module android.Module) bool { _, ok := module.(*Library) return ok } func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_import") } func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { return &librarySdkMemberProperties{} } type librarySdkMemberProperties struct { android.SdkMemberPropertiesBase JarToExport android.Path `android:"arch_variant"` AidlIncludeDirs android.Paths // The list of permitted packages that need to be passed to the prebuilts as they are used to // create the updatable-bcp-packages.txt file. PermittedPackages []string // The value of the min_sdk_version property, translated into a number where possible. MinSdkVersion *string `supported_build_releases:"Tiramisu+"` DexPreoptProfileGuided *bool `supported_build_releases:"UpsideDownCake+"` } func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { j := variant.(*Library) p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(ctx, j) p.AidlIncludeDirs = j.AidlIncludeDirs() p.PermittedPackages = j.PermittedPackagesForUpdatableBootJars() // If the min_sdk_version was set then add the canonical representation of the API level to the // snapshot. if j.deviceProperties.Min_sdk_version != nil { canonical := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String()) p.MinSdkVersion = proptools.StringPtr(canonical) } if j.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided { p.DexPreoptProfileGuided = proptools.BoolPtr(true) } } func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { builder := ctx.SnapshotBuilder() memberType := ctx.MemberType().(*librarySdkMemberType) exportedJar := p.JarToExport if exportedJar != nil { // Delegate the creation of the snapshot relative path to the member type. snapshotRelativeJavaLibPath := memberType.snapshotPathGetter(ctx, p.OsPrefix(), ctx.Name()) // Copy the exported jar to the snapshot. builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath) propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath}) } if p.MinSdkVersion != nil { propertySet.AddProperty("min_sdk_version", *p.MinSdkVersion) } if len(p.PermittedPackages) > 0 { propertySet.AddProperty("permitted_packages", p.PermittedPackages) } dexPreoptSet := propertySet.AddPropertySet("dex_preopt") if p.DexPreoptProfileGuided != nil { dexPreoptSet.AddProperty("profile_guided", proptools.Bool(p.DexPreoptProfileGuided)) } // Do not copy anything else to the snapshot. if memberType.onlyCopyJarToSnapshot { return } aidlIncludeDirs := p.AidlIncludeDirs if len(aidlIncludeDirs) != 0 { sdkModuleContext := ctx.SdkModuleContext() for _, dir := range aidlIncludeDirs { // TODO(jiyong): copy parcelable declarations only aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil) for _, file := range aidlFiles { builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file)) } } // TODO(b/151933053) - add aidl include dirs property } } // java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well. // // By default, a java_library has a single variant that produces a `.jar` file containing `.class` files that were // compiled against the device bootclasspath. This jar is not suitable for installing on a device, but can be used // as a `static_libs` dependency of another module. // // Specifying `installable: true` will product a `.jar` file containing `classes.dex` files, suitable for installing on // a device. // // Specifying `host_supported: true` will produce two variants, one compiled against the device bootclasspath and one // compiled against the host bootclasspath. func LibraryFactory() android.Module { module := &Library{} module.addHostAndDeviceProperties() module.initModuleAndImport(module) android.InitApexModule(module) android.InitBazelModule(module) InitJavaModule(module, android.HostAndDeviceSupported) return module } // java_library_static is an obsolete alias for java_library. func LibraryStaticFactory() android.Module { return LibraryFactory() } // java_library_host builds and links sources into a `.jar` file for the host. // // A java_library_host has a single variant that produces a `.jar` file containing `.class` files that were // compiled against the host bootclasspath. func LibraryHostFactory() android.Module { module := &Library{} module.addHostProperties() module.Module.properties.Installable = proptools.BoolPtr(true) android.InitApexModule(module) android.InitBazelModule(module) InitJavaModule(module, android.HostSupported) return module } // // Java Tests // // Test option struct. type TestOptions struct { android.CommonTestOptions // a list of extra test configuration files that should be installed with the module. Extra_test_configs []string `android:"path,arch_variant"` // Extra