platform_build_soong/java/java.go

1826 lines
57 KiB
Go
Raw Normal View History

// 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"
"strconv"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/java/config"
"android/soong/tradefed"
)
func init() {
android.RegisterModuleType("java_defaults", defaultsFactory)
android.RegisterModuleType("java_library", LibraryFactory)
android.RegisterModuleType("java_library_static", LibraryFactory)
android.RegisterModuleType("java_library_host", LibraryHostFactory)
android.RegisterModuleType("java_binary", BinaryFactory)
android.RegisterModuleType("java_binary_host", BinaryHostFactory)
android.RegisterModuleType("java_test", TestFactory)
android.RegisterModuleType("java_test_host", TestHostFactory)
android.RegisterModuleType("java_import", ImportFactory)
android.RegisterModuleType("java_import_host", ImportFactoryHost)
android.RegisterSingletonType("logtags", LogtagsSingleton)
}
// TODO:
// Autogenerated files:
// Renderscript
// Post-jar passes:
// Proguard
// Rmtypedefs
// DroidDoc
// Findbugs
type CompilerProperties struct {
// list of source files used to compile the Java module. May be .java, .logtags, .proto,
// or .aidl files.
Srcs []string `android:"arch_variant"`
// list of source files that should not be used to build the Java module.
// This is most useful in the arch/multilib variants to remove non-common files
Exclude_srcs []string `android:"arch_variant"`
// list of directories containing Java resources
Java_resource_dirs []string `android:"arch_variant"`
// list of directories that should be excluded from java_resource_dirs
Exclude_java_resource_dirs []string `android:"arch_variant"`
// list of files to use as Java resources
Java_resources []string `android:"arch_variant"`
// list of files that should be excluded from java_resources and java_resource_dirs
Exclude_java_resources []string `android:"arch_variant"`
// don't build against the default libraries (bootclasspath, legacy-test, core-junit,
// ext, and framework for device targets)
No_standard_libs *bool
// don't build against the framework libraries (legacy-test, core-junit,
// ext, and framework for device targets)
No_framework_libs *bool
// list of module-specific flags that will be used for javac compiles
Javacflags []string `android:"arch_variant"`
// list of of java libraries that will be in the classpath
Libs []string `android:"arch_variant"`
// list of java libraries that will be compiled into the resulting jar
Static_libs []string `android:"arch_variant"`
// manifest file to be included in resulting jar
Manifest *string
// if not blank, run jarjar using the specified rules file
Jarjar_rules *string `android:"arch_variant"`
// If not blank, set the java version passed to javac as -source and -target
Java_version *string
// If set to true, allow this module to be dexed and installed on devices. Has no
// effect on host modules, which are always considered installable.
Installable *bool
// If set to true, include sources used to compile the module in to the final jar
Include_srcs *bool
// List of modules to use as annotation processors
Annotation_processors []string
// List of classes to pass to javac to use as annotation processors
Annotation_processor_classes []string
// The number of Java source entries each Javac instance can process
Javac_shard_size *int64
// Add host jdk tools.jar to bootclasspath
Use_tools_jar *bool
Openjdk9 struct {
// List of source files that should only be used when passing -source 1.9
Srcs []string
// List of javac flags that should only be used when passing -source 1.9
Javacflags []string
}
// When compiling language level 9+ .java code in packages that are part of
// a system module, patch_module names the module that your sources and
// dependencies should be patched into. The Android runtime currently
// doesn't implement the JEP 261 module system so this option is only
// supported at compile time. It should only be needed to compile tests in
// packages that exist in libcore and which are inconvenient to move
// elsewhere.
Patch_module *string `android:"arch_variant"`
Jacoco struct {
// List of classes to include for instrumentation with jacoco to collect coverage
// information at runtime when building with coverage enabled. If unset defaults to all
// classes.
// Supports '*' as the last character of an entry in the list as a wildcard match.
// If preceded by '.' it matches all classes in the package and subpackages, otherwise
// it matches classes in the package that have the class name as a prefix.
Include_filter []string
// List of classes to exclude from instrumentation with jacoco to collect coverage
// information at runtime when building with coverage enabled. Overrides classes selected
// by the include_filter property.
// Supports '*' as the last character of an entry in the list as a wildcard match.
// If preceded by '.' it matches all classes in the package and subpackages, otherwise
// it matches classes in the package that have the class name as a prefix.
Exclude_filter []string
}
Errorprone struct {
// List of javac flags that should only be used when running errorprone.
Javacflags []string
}
Proto struct {
// List of extra options that will be passed to the proto generator.
Output_params []string
}
Instrument bool `blueprint:"mutated"`
}
type CompilerDeviceProperties struct {
// list of module-specific flags that will be used for dex compiles
Dxflags []string `android:"arch_variant"`
// if not blank, set to the version of the sdk to compile against. Defaults to compiling against the current
// sdk if platform_apis is not set.
Sdk_version *string
// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
// Defaults to sdk_version if not set.
Min_sdk_version *string
// if true, compile against the platform APIs instead of an SDK.
Platform_apis *bool
Aidl struct {
// Top level directories to pass to aidl tool
Include_dirs []string
// Directories rooted at the Android.bp file to pass to aidl tool
Local_include_dirs []string
// directories that should be added as include directories for any aidl sources of modules
// that depend on this module, as well as to aidl for this module.
Export_include_dirs []string
// whether to generate traces (for systrace) for this interface
Generate_traces *bool
// whether to generate Binder#GetTransaction name method.
Generate_get_transaction_name *bool
}
// If true, export a copy of the module as a -hostdex module for host testing.
Hostdex *bool
// If set to true, compile dex regardless of installable. Defaults to false.
Compile_dex *bool
Dex_preopt struct {
// If false, prevent dexpreopting and stripping the dex file from the final jar. Defaults to
// true.
Enabled *bool
// If true, generate an app image (.art file) for this module.
App_image *bool
// If true, use a checked-in profile to guide optimization. Defaults to false unless
// a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR
// that matches the name of this module, in which case it is defaulted to true.
Profile_guided *bool
// If set, provides the path to profile relative to the Android.bp file. If not set,
// defaults to searching for a file that matches the name of this module in the default
// profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
Profile *string
}
Optimize struct {
// If false, disable all optimization. Defaults to true for android_app and android_test
// modules, false for java_library and java_test modules.
Enabled *bool
// If true, optimize for size by removing unused code. Defaults to true for apps,
// false for libraries and tests.
Shrink *bool
// If true, optimize bytecode. Defaults to false.
Optimize *bool
// If true, obfuscate bytecode. Defaults to false.
Obfuscate *bool
// If true, do not use the flag files generated by aapt that automatically keep
// classes referenced by the app manifest. Defaults to false.
No_aapt_flags *bool
// Flags to pass to proguard.
Proguard_flags []string
// Specifies the locations of files containing proguard flags.
Proguard_flags_files []string
}
// When targeting 1.9, override the modules to use with --system
System_modules *string
}
// Module contains the properties and members used by all java module types
type Module struct {
android.ModuleBase
android.DefaultableModuleBase
properties CompilerProperties
protoProperties android.ProtoProperties
deviceProperties CompilerDeviceProperties
// jar file containing header classes including static library dependencies, suitable for
// inserting into the bootclasspath/classpath of another compile
headerJarFile android.Path
// jar file containing implementation classes including static library dependencies but no
// resources
implementationJarFile android.Path
// jar file containing only resources including from static library dependencies
resourceJar android.Path
// jar file containing implementation classes and resources including static library
// dependencies
implementationAndResourcesJar android.Path
// output file containing classes.dex and resources
dexJarFile android.Path
// output file containing uninstrumented classes that will be instrumented by jacoco
jacocoReportClassesFile android.Path
// output file containing mapping of obfuscated names
proguardDictionary android.Path
// output file of the module, which may be a classes jar or a dex jar
outputFile android.Path
exportAidlIncludeDirs android.Paths
logtagsSrcs android.Paths
// installed file for binary dependency
installFile android.Path
// list of .java files and srcjars that was passed to javac
compiledJavaSrcs android.Paths
compiledSrcJars android.Paths
// list of extra progurad flag files
extraProguardFlagFiles android.Paths
// list of SDK lib names that this java moudule is exporting
exportedSdkLibs []string
// list of source files, collected from compiledJavaSrcs and compiledSrcJars
// filter out Exclude_srcs, will be used by android.IDEInfo struct
expandIDEInfoCompiledSrcs []string
}
func (j *Module) Srcs() android.Paths {
return android.Paths{j.outputFile}
}
var _ android.SourceFileProducer = (*Module)(nil)
type Dependency interface {
HeaderJars() android.Paths
ImplementationJars() android.Paths
ResourceJars() android.Paths
ImplementationAndResourcesJars() android.Paths
AidlIncludeDirs() android.Paths
ExportedSdkLibs() []string
}
type SdkLibraryDependency interface {
HeaderJars(linkType linkType) android.Paths
ImplementationJars(linkType linkType) android.Paths
}
type SrcDependency interface {
CompiledSrcs() android.Paths
CompiledSrcJars() android.Paths
}
func (j *Module) CompiledSrcs() android.Paths {
return j.compiledJavaSrcs
}
func (j *Module) CompiledSrcJars() android.Paths {
return j.compiledSrcJars
}
var _ SrcDependency = (*Module)(nil)
func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
android.InitAndroidArchModule(module, hod, android.MultilibCommon)
android.InitDefaultableModule(module)
}
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
}
type jniDependencyTag struct {
blueprint.BaseDependencyTag
target android.Target
}
var (
staticLibTag = dependencyTag{name: "staticlib"}
libTag = dependencyTag{name: "javalib"}
annoTag = dependencyTag{name: "annotation processor"}
bootClasspathTag = dependencyTag{name: "bootclasspath"}
systemModulesTag = dependencyTag{name: "system modules"}
frameworkResTag = dependencyTag{name: "framework-res"}
frameworkApkTag = dependencyTag{name: "framework-apk"}
kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"}
proguardRaiseTag = dependencyTag{name: "proguard-raise"}
)
type sdkDep struct {
useModule, useFiles, useDefaultLibs, invalidVersion bool
modules []string
systemModules string
frameworkResModule string
jars android.Paths
aidl android.Path
}
type jniLib struct {
name string
path android.Path
target android.Target
}
func (j *Module) shouldInstrument(ctx android.BaseContext) bool {
return j.properties.Instrument && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
}
func (j *Module) shouldInstrumentStatic(ctx android.BaseContext) bool {
return j.shouldInstrument(ctx) &&
(ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_STATIC") ||
ctx.Config().UnbundledBuild())
}
func (j *Module) sdkVersion() string {
return String(j.deviceProperties.Sdk_version)
}
func (j *Module) minSdkVersion() string {
if j.deviceProperties.Min_sdk_version != nil {
return *j.deviceProperties.Min_sdk_version
}
return j.sdkVersion()
}
type sdkContext interface {
// sdkVersion eturns the sdk_version property of the current module, or an empty string if it is not set.
sdkVersion() string
// minSdkVersion returns the min_sdk_version property of the current module, or sdkVersion() if it is not set.
minSdkVersion() string
}
func sdkVersionOrDefault(ctx android.BaseContext, v string) string {
switch v {
case "", "current", "system_current", "test_current", "core_current", "core_platform_current":
return ctx.Config().DefaultAppTargetSdk()
default:
return v
}
}
// Returns a sdk version as a number. For modules targeting an unreleased SDK (meaning it does not yet have a number)
// it returns android.FutureApiLevel (10000).
func sdkVersionToNumber(ctx android.BaseContext, v string) (int, error) {
switch v {
case "", "current", "test_current", "system_current", "core_current", "core_platform_current":
return ctx.Config().DefaultAppTargetSdkInt(), nil
default:
n := android.GetNumericSdkVersion(v)
if i, err := strconv.Atoi(n); err != nil {
return -1, fmt.Errorf("invalid sdk version %q", n)
} else {
return i, nil
}
}
}
func sdkVersionToNumberAsString(ctx android.BaseContext, v string) (string, error) {
n, err := sdkVersionToNumber(ctx, v)
if err != nil {
return "", err
}
return strconv.Itoa(n), nil
}
func decodeSdkDep(ctx android.BaseContext, sdkContext sdkContext) sdkDep {
v := sdkContext.sdkVersion()
i, err := sdkVersionToNumber(ctx, v)
if err != nil {
ctx.PropertyErrorf("sdk_version", "%s", err)
return sdkDep{}
}
Add PLATFORM_SYSTEMSDK_VERSIONS and BOARD_SYSTEMSDK_VERSIONS PLATFORM_SYSTEMSDK_VERSIONS is the list of System SDK versions that the platform is supporting. Contrary to the public SDK where platform essentially supports all previous SDK versions, platform support only a few recent System SDK versions, since some of old System APIs are gradually deprecated, removed from the following SDKs and then finally deleted from the platform. This will be part of the framework manifest. The list can be specified by setting PLATFORM_SYSTEMSDK_MIN_VERSION. If it is set to an old version number, then System SDKs from the version to the current version (PLATFORM_SDK_VERSION) are considered to be supported by the platform. If PLATFORM_SYSTEMSDK_MIN_VERSION is not set, only the latest System SDK version is supported. Next, BOARD_SYSTEMSDK_VERSIONS is the list of System SDK versions that the device is using. This is put to the device compatibility matrix device is using. The device and the platform is considered as compatible only BOARD_SYSTEMSDK_VERSIONS in the device compatibility matrix are in the PLATFORM_SYSTEMSDK_VERSIONS in the framework manifest. When BOARD_SYSTEMSDK_VERSIONS is set, a Java app or library in vendor or odm partitions which didn't specify LOCAL_SDK_VERSION is forced to use System SDK. Also, the build system does the additional integrity check to ensure that LOCAL_SDK_VERSION is within BOARD_SYSTEMSDK_VERSIONS or PLATFORM_SYSTEMSDK_VERSIONS (if BOARD_SYSTEMSDK_VERSIONS isn't set). Bug: 69088799 Test: m -j Test: BOARD_SYSTEMSDK_VERSIONS=P m -j Change-Id: Id38f02b4be86710411be22bc28109e6894f8a483
2018-01-15 14:05:10 +08:00
// Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
// or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set)
if strings.HasPrefix(v, "system_") && i != android.FutureApiLevel {
allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions()
if ctx.DeviceSpecific() || ctx.SocSpecific() {
if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 {
allowed_versions = ctx.DeviceConfig().SystemSdkVersions()
}
}
version := strings.TrimPrefix(v, "system_")
if len(allowed_versions) > 0 && !android.InList(version, allowed_versions) {
ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
v, allowed_versions)
}
}
toPrebuilt := func(sdk string) sdkDep {
var api, v string
if strings.Contains(sdk, "_") {
t := strings.Split(sdk, "_")
api = t[0]
v = t[1]
} else {
api = "public"
v = sdk
}
dir := filepath.Join("prebuilts", "sdk", v, api)
jar := filepath.Join(dir, "android.jar")
// There's no aidl for other SDKs yet.
// TODO(77525052): Add aidl files for other SDKs too.
public_dir := filepath.Join("prebuilts", "sdk", v, "public")
aidl := filepath.Join(public_dir, "framework.aidl")
jarPath := android.ExistentPathForSource(ctx, jar)
aidlPath := android.ExistentPathForSource(ctx, aidl)
lambdaStubsPath := android.PathForSource(ctx, config.SdkLambdaStubsPath)
if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
return sdkDep{
invalidVersion: true,
modules: []string{fmt.Sprintf("sdk_%s_%s_android", api, v)},
}
}
if !jarPath.Valid() {
ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, jar)
return sdkDep{}
}
if !aidlPath.Valid() {
ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, aidl)
return sdkDep{}
}
return sdkDep{
useFiles: true,
jars: android.Paths{jarPath.Path(), lambdaStubsPath},
aidl: aidlPath.Path(),
}
}
toModule := func(m, r string) sdkDep {
ret := sdkDep{
useModule: true,
modules: []string{m, config.DefaultLambdaStubsLibrary},
systemModules: m + "_system_modules",
frameworkResModule: r,
}
if m == "core.current.stubs" {
ret.systemModules = "core-system-modules"
} else if m == "core.platform.api.stubs" {
ret.systemModules = "core-platform-api-stubs-system-modules"
}
return ret
}
if ctx.Config().UnbundledBuild() && v != "" {
return toPrebuilt(v)
}
switch v {
case "":
return sdkDep{
useDefaultLibs: true,
frameworkResModule: "framework-res",
}
case "current":
return toModule("android_stubs_current", "framework-res")
case "system_current":
return toModule("android_system_stubs_current", "framework-res")
case "test_current":
return toModule("android_test_stubs_current", "framework-res")
case "core_current":
return toModule("core.current.stubs", "")
case "core_platform_current":
return toModule("core.platform.api.stubs", "")
default:
return toPrebuilt(v)
}
}
func (j *Module) deps(ctx android.BottomUpMutatorContext) {
if ctx.Device() {
if !Bool(j.properties.No_standard_libs) {
sdkDep := decodeSdkDep(ctx, sdkContext(j))
if sdkDep.useDefaultLibs {
ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
2018-09-11 23:21:05 +08:00
ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
if !Bool(j.properties.No_framework_libs) {
ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
}
} else if sdkDep.useModule {
2018-09-11 23:21:05 +08:00
ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.modules...)
if Bool(j.deviceProperties.Optimize.Enabled) {
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
}
}
} else if j.deviceProperties.System_modules == nil {
ctx.PropertyErrorf("no_standard_libs",
"system_modules is required to be set when no_standard_libs is true, did you mean no_framework_libs?")
2018-09-11 23:21:05 +08:00
} else if *j.deviceProperties.System_modules != "none" {
ctx.AddVariationDependencies(nil, systemModulesTag, *j.deviceProperties.System_modules)
}
if (ctx.ModuleName() == "framework") || (ctx.ModuleName() == "framework-annotation-proc") {
ctx.AddVariationDependencies(nil, frameworkResTag, "framework-res")
}
if ctx.ModuleName() == "android_stubs_current" ||
ctx.ModuleName() == "android_system_stubs_current" ||
ctx.ModuleName() == "android_test_stubs_current" {
ctx.AddVariationDependencies(nil, frameworkApkTag, "framework-res")
}
}
ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
ctx.AddFarVariationDependencies([]blueprint.Variation{
{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
}, annoTag, j.properties.Annotation_processors...)
android.ExtractSourcesDeps(ctx, j.properties.Srcs)
android.ExtractSourcesDeps(ctx, j.properties.Exclude_srcs)
android.ExtractSourcesDeps(ctx, j.properties.Java_resources)
android.ExtractSourceDeps(ctx, j.properties.Manifest)
if j.hasSrcExt(".proto") {
protoDeps(ctx, &j.protoProperties)
}
if j.hasSrcExt(".kt") {
// TODO(ccross): move this to a mutator pass that can tell if generated sources contain
// Kotlin files
ctx.AddVariationDependencies(nil, kotlinStdlibTag, "kotlin-stdlib")
}
if j.shouldInstrumentStatic(ctx) {
ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
}
}
func hasSrcExt(srcs []string, ext string) bool {
for _, src := range srcs {
if filepath.Ext(src) == ext {
return true
}
}
return false
}
func shardPaths(paths android.Paths, shardSize int) []android.Paths {
ret := make([]android.Paths, 0, (len(paths)+shardSize-1)/shardSize)
for len(paths) > shardSize {
ret = append(ret, paths[0:shardSize])
paths = paths[shardSize:]
}
if len(paths) > 0 {
ret = append(ret, paths)
}
return ret
}
func (j *Module) hasSrcExt(ext string) bool {
return hasSrcExt(j.properties.Srcs, ext)
}
func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
aidlIncludeDirs android.Paths) []string {
aidlIncludes := android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Local_include_dirs)
aidlIncludes = append(aidlIncludes,
android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)...)
aidlIncludes = append(aidlIncludes,
android.PathsForSource(ctx, j.deviceProperties.Aidl.Include_dirs)...)
flags := []string{"-b"}
if aidlPreprocess.Valid() {
flags = append(flags, "-p"+aidlPreprocess.String())
} else {
flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
}
flags = append(flags, android.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I"))
flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() {
flags = append(flags, "-I"+src.String())
}
if Bool(j.deviceProperties.Aidl.Generate_traces) {
flags = append(flags, "-t")
}
if Bool(j.deviceProperties.Aidl.Generate_get_transaction_name) {
flags = append(flags, "--transaction_names")
}
return flags
}
type deps struct {
classpath classpath
bootClasspath classpath
processorPath classpath
staticJars android.Paths
staticHeaderJars android.Paths
staticResourceJars android.Paths
aidlIncludeDirs android.Paths
srcs android.Paths
srcJars android.Paths
systemModules android.Path
aidlPreprocess android.OptionalPath
kotlinStdlib android.Paths
}
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)))
}
}
}
type linkType int
const (
javaCore linkType = iota
javaSdk
javaSystem
javaPlatform
)
func getLinkType(m *Module, name string) linkType {
ver := m.sdkVersion()
noStdLibs := Bool(m.properties.No_standard_libs)
switch {
case name == "core.current.stubs" || ver == "core_current" ||
name == "core.platform.api.stubs" || ver == "core_platform_current" ||
noStdLibs || name == "stub-annotations" || name == "private-stub-annotations-jar":
return javaCore
case name == "android_system_stubs_current" || strings.HasPrefix(ver, "system_"):
return javaSystem
case name == "android_test_stubs_current" || strings.HasPrefix(ver, "test_"):
return javaPlatform
case name == "android_stubs_current" || ver == "current":
return javaSdk
case ver == "":
return javaPlatform
default:
if _, err := strconv.Atoi(ver); err != nil {
panic(fmt.Errorf("expected sdk_version to be a number, got %q", ver))
}
return javaSdk
}
}
func checkLinkType(ctx android.ModuleContext, from *Module, to *Library, tag dependencyTag) {
if ctx.Host() {
return
}
myLinkType := getLinkType(from, ctx.ModuleName())
otherLinkType := getLinkType(&to.Module, ctx.OtherModuleName(to))
commonMessage := "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source."
switch myLinkType {
case javaCore:
if otherLinkType != javaCore {
ctx.ModuleErrorf("compiles against core Java API, but dependency %q is compiling against non-core Java APIs."+commonMessage,
ctx.OtherModuleName(to))
}
break
case javaSdk:
if otherLinkType != javaCore && otherLinkType != javaSdk {
ctx.ModuleErrorf("compiles against Android API, but dependency %q is compiling against non-public Android API."+commonMessage,
ctx.OtherModuleName(to))
}
break
case javaSystem:
if otherLinkType == javaPlatform {
ctx.ModuleErrorf("compiles against system API, but dependency %q is compiling against private API."+commonMessage,
ctx.OtherModuleName(to))
}
break
case javaPlatform:
// no restriction on link-type
break
}
}
func (j *Module) collectDeps(ctx android.ModuleContext) deps {
var deps deps
if ctx.Device() {
sdkDep := decodeSdkDep(ctx, sdkContext(j))
if sdkDep.invalidVersion {
ctx.AddMissingDependencies(sdkDep.modules)
} else if sdkDep.useFiles {
// sdkDep.jar is actually equivalent to turbine header.jar.
deps.classpath = append(deps.classpath, sdkDep.jars...)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, sdkDep.aidl)
}
}
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
if _, ok := tag.(*jniDependencyTag); ok {
// Handled by AndroidApp.collectJniDeps
return
}
if to, ok := module.(*Library); ok {
switch tag {
case bootClasspathTag, libTag, staticLibTag:
checkLinkType(ctx, j, to, tag.(dependencyTag))
}
}
switch dep := module.(type) {
case Dependency:
switch tag {
case bootClasspathTag:
deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
case libTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
// sdk lib names from dependencies are re-exported
j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
case staticLibTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
// sdk lib names from dependencies are re-exported
j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
case annoTag:
deps.processorPath = append(deps.processorPath, dep.ImplementationAndResourcesJars()...)
case frameworkResTag:
if (ctx.ModuleName() == "framework") || (ctx.ModuleName() == "framework-annotation-proc") {
// framework.jar has a one-off dependency on the R.java and Manifest.java files
// generated by framework-res.apk
deps.srcJars = append(deps.srcJars, dep.(*AndroidApp).aaptSrcJar)
}
case frameworkApkTag:
if ctx.ModuleName() == "android_stubs_current" ||
ctx.ModuleName() == "android_system_stubs_current" ||
ctx.ModuleName() == "android_test_stubs_current" {
// framework stubs.jar need to depend on framework-res.apk, in order to pull the
// resource files out of there for aapt.
//
// Normally the package rule runs aapt, which includes the resource,
// but we're not running that in our package rule so just copy in the
// resource files here.
deps.staticResourceJars = append(deps.staticResourceJars, dep.(*AndroidApp).exportPackage)
}
case kotlinStdlibTag:
deps.kotlinStdlib = dep.HeaderJars()
}
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
case SdkLibraryDependency:
switch tag {
case libTag:
deps.classpath = append(deps.classpath, dep.HeaderJars(getLinkType(j, ctx.ModuleName()))...)
// names of sdk libs that are directly depended are exported
j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
default:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
case android.SourceFileProducer:
switch tag {
case libTag:
checkProducesJars(ctx, dep)
deps.classpath = append(deps.classpath, dep.Srcs()...)
case staticLibTag:
checkProducesJars(ctx, dep)
deps.classpath = append(deps.classpath, dep.Srcs()...)
deps.staticJars = append(deps.staticJars, dep.Srcs()...)
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
case android.DefaultsDepTag, android.SourceDepTag:
// Nothing to do
default:
ctx.ModuleErrorf("dependency on genrule %q may only be in srcs, libs, or static_libs", otherName)
}
default:
switch tag {
case android.DefaultsDepTag, android.SourceDepTag:
// Nothing to do
case systemModulesTag:
if deps.systemModules != nil {
panic("Found two system module dependencies")
}
sm := module.(*SystemModules)
if sm.outputFile == nil {
panic("Missing directory for system module dependency")
}
deps.systemModules = sm.outputFile
default:
ctx.ModuleErrorf("depends on non-java module %q", otherName)
}
}
})
j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs)
return deps
}
func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) string {
var ret string
sdk, err := sdkVersionToNumber(ctx, sdkContext.sdkVersion())
if err != nil {
ctx.PropertyErrorf("sdk_version", "%s", err)
}
if javaVersion != "" {
ret = javaVersion
} else if ctx.Device() && sdk <= 23 {
ret = "1.7"
} else if ctx.Device() && sdk <= 28 || !ctx.Config().TargetOpenJDK9() {
ret = "1.8"
} else if ctx.Device() && sdkContext.sdkVersion() != "" && sdk == android.FutureApiLevel {
// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
ret = "1.8"
} else {
ret = "1.9"
}
return ret
}
func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaBuilderFlags {
var flags javaBuilderFlags
2018-09-11 23:21:05 +08:00
// javaVersion flag.
flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j))
// javac flags.
javacFlags := j.properties.Javacflags
2018-09-11 23:21:05 +08:00
if flags.javaVersion == "1.9" {
javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
}
if ctx.Config().MinimizeJavaDebugInfo() {
// Override the -g flag passed globally to remove local variable debug info to reduce
// disk and memory usage.
javacFlags = append(javacFlags, "-g:source,lines")
}
if ctx.Config().RunErrorProne() {
if config.ErrorProneClasspath == nil {
ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
}
errorProneFlags := []string{
"-Xplugin:ErrorProne",
"${config.ErrorProneChecks}",
}
errorProneFlags = append(errorProneFlags, j.properties.Errorprone.Javacflags...)
flags.errorProneExtraJavacFlags = "${config.ErrorProneFlags} " +
"'" + strings.Join(errorProneFlags, " ") + "'"
flags.errorProneProcessorPath = classpath(android.PathsForSource(ctx, config.ErrorProneClasspath))
}
// classpath
flags.bootClasspath = append(flags.bootClasspath, deps.bootClasspath...)
flags.classpath = append(flags.classpath, deps.classpath...)
flags.processorPath = append(flags.processorPath, deps.processorPath...)
2018-09-11 23:21:05 +08:00
if len(flags.bootClasspath) == 0 && ctx.Host() && flags.javaVersion != "1.9" &&
!Bool(j.properties.No_standard_libs) &&
inList(flags.javaVersion, []string{"1.6", "1.7", "1.8"}) {
// Give host-side tools a version of OpenJDK's standard libraries
// close to what they're targeting. As of Dec 2017, AOSP is only
// bundling OpenJDK 8 and 9, so nothing < 8 is available.
//
// When building with OpenJDK 8, the following should have no
// effect since those jars would be available by default.
//
// When building with OpenJDK 9 but targeting a version < 1.8,
// putting them on the bootclasspath means that:
// a) code can't (accidentally) refer to OpenJDK 9 specific APIs
// b) references to existing APIs are not reinterpreted in an
// OpenJDK 9-specific way, eg. calls to subclasses of
// java.nio.Buffer as in http://b/70862583
java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
flags.bootClasspath = append(flags.bootClasspath,
android.PathForSource(ctx, java8Home, "jre/lib/jce.jar"),
android.PathForSource(ctx, java8Home, "jre/lib/rt.jar"))
if Bool(j.properties.Use_tools_jar) {
flags.bootClasspath = append(flags.bootClasspath,
android.PathForSource(ctx, java8Home, "lib/tools.jar"))
}
}
2018-09-11 23:21:05 +08:00
if j.properties.Patch_module != nil && flags.javaVersion == "1.9" {
patchClasspath := ".:" + flags.classpath.FormJavaClassPath("")
javacFlags = append(javacFlags, "--patch-module="+String(j.properties.Patch_module)+"="+patchClasspath)
}
// systemModules
if deps.systemModules != nil {
flags.systemModules = append(flags.systemModules, deps.systemModules)
}
// aidl flags.
aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
if len(aidlFlags) > 0 {
// optimization.
ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
flags.aidlFlags = "$aidlFlags"
}
if len(javacFlags) > 0 {
// optimization.
ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
flags.javacFlags = "$javacFlags"
}
return flags
}
func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path) {
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
deps := j.collectDeps(ctx)
flags := j.collectBuilderFlags(ctx, deps)
2018-09-11 23:21:05 +08:00
if flags.javaVersion == "1.9" {
j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
}
srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
if hasSrcExt(srcFiles.Strings(), ".proto") {
flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
}
srcFiles = j.genSources(ctx, srcFiles, flags)
srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...)
srcJars = append(srcJars, extraSrcJars...)
// Collect source files from compiledJavaSrcs, compiledSrcJars and filter out Exclude_srcs
// that IDEInfo struct will use
j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, srcFiles.Strings()...)
jarName := ctx.ModuleName() + ".jar"
javaSrcFiles := srcFiles.FilterByExt(".java")
var uniqueSrcFiles android.Paths
set := make(map[string]bool)
for _, v := range javaSrcFiles {
if _, found := set[v.String()]; !found {
set[v.String()] = true
uniqueSrcFiles = append(uniqueSrcFiles, v)
}
}
var kotlinJars android.Paths
if srcFiles.HasExt(".kt") {
// If there are kotlin files, compile them first but pass all the kotlin and java files
// kotlinc will use the java files to resolve types referenced by the kotlin files, but
// won't emit any classes for them.
flags.kotlincFlags = "-no-stdlib"
if ctx.Device() {
flags.kotlincFlags += " -no-jdk"
}
var kotlinSrcFiles android.Paths
kotlinSrcFiles = append(kotlinSrcFiles, uniqueSrcFiles...)
kotlinSrcFiles = append(kotlinSrcFiles, srcFiles.FilterByExt(".kt")...)
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.bootClasspath...)
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.kotlinStdlib...)
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.classpath...)
kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
TransformKotlinToClasses(ctx, kotlinJar, kotlinSrcFiles, srcJars, flags)
if ctx.Failed() {
return
}
// Make javac rule depend on the kotlinc rule
flags.classpath = append(flags.classpath, deps.kotlinStdlib...)
flags.classpath = append(flags.classpath, kotlinJar)
// Jar kotlin classes into the final jar after javac
kotlinJars = append(kotlinJars, kotlinJar)
kotlinJars = append(kotlinJars, deps.kotlinStdlib...)
}
jars := append(android.Paths(nil), kotlinJars...)
// Store the list of .java files that was passed to javac
j.compiledJavaSrcs = uniqueSrcFiles
j.compiledSrcJars = srcJars
enable_sharding := false
if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enable_sharding = true
if len(j.properties.Annotation_processors) != 0 ||
len(j.properties.Annotation_processor_classes) != 0 {
ctx.PropertyErrorf("javac_shard_size",
"%q cannot be set when annotation processors are enabled.",
j.properties.Javac_shard_size)
}
}
j.headerJarFile = j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName, kotlinJars)
if ctx.Failed() {
return
}
}
if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 {
var extraJarDeps android.Paths
if ctx.Config().RunErrorProne() {
// If error-prone is enabled, add an additional rule to compile the java files into
// a separate set of classes (so that they don't overwrite the normal ones and require
// a rebuild when error-prone is turned off).
// TODO(ccross): Once we always compile with javac9 we may be able to conditionally
// enable error-prone without affecting the output class files.
errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
RunErrorProne(ctx, errorprone, uniqueSrcFiles, srcJars, flags)
extraJarDeps = append(extraJarDeps, errorprone)
}
if enable_sharding {
flags.classpath = append(flags.classpath, j.headerJarFile)
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
if len(uniqueSrcFiles) > 0 {
shardSrcs = shardPaths(uniqueSrcFiles, shardSize)
for idx, shardSrc := range shardSrcs {
classes := android.PathForModuleOut(ctx, "javac", jarName+strconv.Itoa(idx))
TransformJavaToClasses(ctx, classes, idx, shardSrc, nil, flags, extraJarDeps)
jars = append(jars, classes)
}
}
if len(srcJars) > 0 {
classes := android.PathForModuleOut(ctx, "javac", jarName+strconv.Itoa(len(shardSrcs)))
TransformJavaToClasses(ctx, classes, len(shardSrcs), nil, srcJars, flags, extraJarDeps)
jars = append(jars, classes)
}
} else {
classes := android.PathForModuleOut(ctx, "javac", jarName)
TransformJavaToClasses(ctx, classes, -1, uniqueSrcFiles, srcJars, flags, extraJarDeps)
jars = append(jars, classes)
}
if ctx.Failed() {
return
}
}
dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs,
j.properties.Exclude_java_resource_dirs, j.properties.Exclude_java_resources)
fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources)
var resArgs []string
var resDeps android.Paths
resArgs = append(resArgs, dirArgs...)
resDeps = append(resDeps, dirDeps...)
resArgs = append(resArgs, fileArgs...)
resDeps = append(resDeps, fileDeps...)
if Bool(j.properties.Include_srcs) {
srcArgs, srcDeps := SourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
resArgs = append(resArgs, srcArgs...)
resDeps = append(resDeps, srcDeps...)
}
if len(resArgs) > 0 {
resourceJar := android.PathForModuleOut(ctx, "res", jarName)
TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps)
j.resourceJar = resourceJar
if ctx.Failed() {
return
}
}
if len(deps.staticResourceJars) > 0 {
var jars android.Paths
if j.resourceJar != nil {
jars = append(jars, j.resourceJar)
}
jars = append(jars, deps.staticResourceJars...)
combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
false, nil, nil)
j.resourceJar = combinedJar
}
jars = append(jars, deps.staticJars...)
jars = append(jars, deps.staticResourceJars...)
var manifest android.OptionalPath
if j.properties.Manifest != nil {
manifest = android.OptionalPathForPath(ctx.ExpandSource(*j.properties.Manifest, "manifest"))
}
// Combine the classes built from sources, any manifests, and any static libraries into
// classes.jar. If there is only one input jar this step will be skipped.
var outputFile android.ModuleOutPath
if len(jars) == 1 && !manifest.Valid() {
if moduleOutPath, ok := jars[0].(android.ModuleOutPath); ok {
// Optimization: skip the combine step if there is nothing to do
// TODO(ccross): this leaves any module-info.class files, but those should only come from
// prebuilt dependencies until we support modules in the platform build, so there shouldn't be
// any if len(jars) == 1.
outputFile = moduleOutPath
} else {
combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Input: jars[0],
Output: combinedJar,
})
outputFile = combinedJar
}
} else {
combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for javac", jars, manifest,
false, nil, nil)
outputFile = combinedJar
}
// jarjar implementation jar if necessary
if j.properties.Jarjar_rules != nil {
jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "jarjar", jarName)
TransformJarJar(ctx, jarjarFile, outputFile, jarjar_rules)
outputFile = jarjarFile
// jarjar resource jar if necessary
if j.resourceJar != nil {
resourceJarJarFile := android.PathForModuleOut(ctx, "res-jarjar", jarName)
TransformJarJar(ctx, resourceJarJarFile, j.resourceJar, jarjar_rules)
j.resourceJar = resourceJarJarFile
}
if ctx.Failed() {
return
}
}
j.implementationJarFile = outputFile
if j.headerJarFile == nil {
j.headerJarFile = j.implementationJarFile
}
if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
if inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
j.properties.Instrument = true
}
}
if j.shouldInstrument(ctx) {
outputFile = j.instrument(ctx, flags, outputFile, jarName)
}
// merge implementation jar with resources if necessary
implementationAndResourcesJar := outputFile
if j.resourceJar != nil {
jars := android.Paths{implementationAndResourcesJar, j.resourceJar}
combinedJar := android.PathForModuleOut(ctx, "withres", jarName)
TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
false, nil, nil)
implementationAndResourcesJar = combinedJar
}
j.implementationAndResourcesJar = implementationAndResourcesJar
if ctx.Device() && (Bool(j.properties.Installable) || Bool(j.deviceProperties.Compile_dex)) {
var dexOutputFile android.ModuleOutPath
dexOutputFile = j.compileDex(ctx, flags, outputFile, jarName)
if ctx.Failed() {
return
}
// merge dex jar with resources if necessary
if j.resourceJar != nil {
jars := android.Paths{dexOutputFile, j.resourceJar}
combinedJar := android.PathForModuleOut(ctx, "dex-withres", jarName)
TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{},
false, nil, nil)
dexOutputFile = combinedJar
}
j.dexJarFile = dexOutputFile
outputFile = dexOutputFile
} else {
outputFile = implementationAndResourcesJar
}
ctx.CheckbuildFile(outputFile)
// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
j.outputFile = outputFile.WithoutRel()
}
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
deps deps, flags javaBuilderFlags, jarName string, extraJars android.Paths) android.Path {
var jars android.Paths
if len(srcFiles) > 0 || len(srcJars) > 0 {
// Compile java sources into turbine.jar.
turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
if ctx.Failed() {
return nil
}
jars = append(jars, turbineJar)
}
jars = append(jars, extraJars...)
// Combine any static header libraries into classes-header.jar. If there is only
// one input jar this step will be skipped.
var headerJar android.Path
jars = append(jars, deps.staticHeaderJars...)
// we cannot skip the combine step for now if there is only one jar
// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{},
false, nil, []string{"META-INF"})
headerJar = combinedJar
if j.properties.Jarjar_rules != nil {
jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
TransformJarJar(ctx, jarjarFile, headerJar, jarjar_rules)
headerJar = jarjarFile
if ctx.Failed() {
return nil
}
}
return headerJar
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
classesJar android.Path, jarName string) android.ModuleOutPath {
specs := j.jacocoModuleToZipCommand(ctx)
jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco-report-classes", jarName)
instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName)
jacocoInstrumentJar(ctx, instrumentedJar, jacocoReportClassesFile, classesJar, specs)
j.jacocoReportClassesFile = jacocoReportClassesFile
return instrumentedJar
}
var _ Dependency = (*Library)(nil)
func (j *Module) HeaderJars() android.Paths {
return android.Paths{j.headerJarFile}
}
func (j *Module) ImplementationJars() android.Paths {
return android.Paths{j.implementationJarFile}
}
func (j *Module) ResourceJars() android.Paths {
if j.resourceJar == nil {
return nil
}
return android.Paths{j.resourceJar}
}
func (j *Module) ImplementationAndResourcesJars() android.Paths {
return android.Paths{j.implementationAndResourcesJar}
}
func (j *Module) AidlIncludeDirs() android.Paths {
return j.exportAidlIncludeDirs
}
func (j *Module) ExportedSdkLibs() []string {
return j.exportedSdkLibs
}
var _ logtagsProducer = (*Module)(nil)
func (j *Module) logtags() android.Paths {
return j.logtagsSrcs
}
// Collect information for opening IDE project files in java/jdeps.go.
func (j *Module) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Deps = append(dpInfo.Deps, j.CompilerDeps()...)
dpInfo.Srcs = append(dpInfo.Srcs, j.expandIDEInfoCompiledSrcs...)
dpInfo.Aidl_include_dirs = append(dpInfo.Aidl_include_dirs, j.deviceProperties.Aidl.Include_dirs...)
if j.properties.Jarjar_rules != nil {
dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, *j.properties.Jarjar_rules)
}
}
func (j *Module) CompilerDeps() []string {
jdeps := []string{}
jdeps = append(jdeps, j.properties.Libs...)
jdeps = append(jdeps, j.properties.Static_libs...)
return jdeps
}
//
// Java libraries (.jar file)
//
type Library struct {
Module
}
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.compile(ctx)
if Bool(j.properties.Installable) || ctx.Host() {
j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
ctx.ModuleName()+".jar", j.outputFile)
}
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
j.deps(ctx)
}
func LibraryFactory() android.Module {
module := &Library{}
module.AddProperties(
&module.Module.properties,
&module.Module.deviceProperties,
&module.Module.protoProperties)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
func LibraryHostFactory() android.Module {
module := &Library{}
module.AddProperties(
&module.Module.properties,
&module.Module.protoProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
InitJavaModule(module, android.HostSupported)
return module
}
//
// Java Tests
//
type testProperties struct {
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
Test_suites []string `android:"arch_variant"`
// the name of the test configuration (for example "AndroidTest.xml") that should be
// installed with the module.
Test_config *string `android:"arch_variant"`
// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
// should be installed with the module.
Test_config_template *string `android:"arch_variant"`
// list of files or filegroup modules that provide data that should be installed alongside
// the test
Data []string
}
type Test struct {
Library
testProperties testProperties
testConfig android.Path
data android.Paths
}
func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template)
j.data = ctx.ExpandSources(j.testProperties.Data, nil)
j.Library.GenerateAndroidBuildActions(ctx)
}
func (j *Test) DepsMutator(ctx android.BottomUpMutatorContext) {
j.deps(ctx)
android.ExtractSourceDeps(ctx, j.testProperties.Test_config)
android.ExtractSourceDeps(ctx, j.testProperties.Test_config_template)
android.ExtractSourcesDeps(ctx, j.testProperties.Data)
}
func TestFactory() android.Module {
module := &Test{}
module.AddProperties(
&module.Module.properties,
&module.Module.deviceProperties,
&module.Module.protoProperties,
&module.testProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
func TestHostFactory() android.Module {
module := &Test{}
module.AddProperties(
&module.Module.properties,
&module.Module.protoProperties,
&module.testProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
InitJavaModule(module, android.HostSupported)
return module
}
//
// Java Binaries (.jar file plus wrapper script)
//
type binaryProperties struct {
// installable script to execute the resulting jar
Wrapper *string
}
type Binary struct {
Library
binaryProperties binaryProperties
isWrapperVariant bool
wrapperFile android.Path
binaryFile android.OutputPath
}
func (j *Binary) HostToolPath() android.OptionalPath {
return android.OptionalPathForPath(j.binaryFile)
}
func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if ctx.Arch().ArchType == android.Common {
// Compile the jar
j.Library.GenerateAndroidBuildActions(ctx)
} else {
// Handle the binary wrapper
j.isWrapperVariant = true
if j.binaryProperties.Wrapper != nil {
j.wrapperFile = ctx.ExpandSource(*j.binaryProperties.Wrapper, "wrapper")
} else {
j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
}
// Depend on the installed jar so that the wrapper doesn't get executed by
// another build rule before the jar has been installed.
jarFile := ctx.PrimaryModule().(*Binary).installFile
j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
ctx.ModuleName(), j.wrapperFile, jarFile)
}
}
func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
if ctx.Arch().ArchType == android.Common {
j.deps(ctx)
} else {
android.ExtractSourceDeps(ctx, j.binaryProperties.Wrapper)
}
}
func BinaryFactory() android.Module {
module := &Binary{}
module.AddProperties(
&module.Module.properties,
&module.Module.deviceProperties,
&module.Module.protoProperties,
&module.binaryProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
android.InitDefaultableModule(module)
return module
}
func BinaryHostFactory() android.Module {
module := &Binary{}
module.AddProperties(
&module.Module.properties,
&module.Module.protoProperties,
&module.binaryProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst)
android.InitDefaultableModule(module)
return module
}
//
// Java prebuilts
//
type ImportProperties struct {
Jars []string
Sdk_version *string
Installable *bool
// List of shared java libs that this module has dependencies to
Libs []string
// List of files to remove from the jar file(s)
Exclude_files []string
// List of directories to remove from the jar file(s)
Exclude_dirs []string
// if set to true, run Jetifier against .jar file. Defaults to false.
Jetifier_enabled *bool
}
type Import struct {
android.ModuleBase
android.DefaultableModuleBase
prebuilt android.Prebuilt
properties ImportProperties
combinedClasspathFile android.Path
exportedSdkLibs []string
}
func (j *Import) sdkVersion() string {
return String(j.properties.Sdk_version)
}
func (j *Import) minSdkVersion() string {
return j.sdkVersion()
}
func (j *Import) Prebuilt() *android.Prebuilt {
return &j.prebuilt
}
func (j *Import) PrebuiltSrcs() []string {
return j.properties.Jars
}
func (j *Import) Name() string {
return j.prebuilt.Name(j.ModuleBase.Name())
}
func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
android.ExtractSourcesDeps(ctx, j.properties.Jars)
ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
}
func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
jars := ctx.ExpandSources(j.properties.Jars, nil)
jarName := ctx.ModuleName() + ".jar"
outputFile := android.PathForModuleOut(ctx, "combined", jarName)
TransformJarsToJar(ctx, outputFile, "for prebuilts", jars, android.OptionalPath{},
false, j.properties.Exclude_files, j.properties.Exclude_dirs)
if Bool(j.properties.Jetifier_enabled) {
inputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "jetifier", jarName)
TransformJetifier(ctx, outputFile, inputFile)
}
j.combinedClasspathFile = outputFile
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
switch dep := module.(type) {
case Dependency:
switch tag {
case libTag, staticLibTag:
// sdk lib names from dependencies are re-exported
j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
}
case SdkLibraryDependency:
switch tag {
case libTag:
// names of sdk libs that are directly depended are exported
j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
}
}
})
j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs)
if Bool(j.properties.Installable) {
ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
ctx.ModuleName()+".jar", outputFile)
}
}
var _ Dependency = (*Import)(nil)
func (j *Import) HeaderJars() android.Paths {
return android.Paths{j.combinedClasspathFile}
}
func (j *Import) ImplementationJars() android.Paths {
return android.Paths{j.combinedClasspathFile}
}
func (j *Import) ResourceJars() android.Paths {
return nil
}
func (j *Import) ImplementationAndResourcesJars() android.Paths {
return android.Paths{j.combinedClasspathFile}
}
func (j *Import) AidlIncludeDirs() android.Paths {
return nil
}
func (j *Import) ExportedSdkLibs() []string {
return j.exportedSdkLibs
}
// Collect information for opening IDE project files in java/jdeps.go.
const (
removedPrefix = "prebuilt_"
)
func (j *Import) IDEInfo(dpInfo *android.IdeInfo) {
dpInfo.Jars = append(dpInfo.Jars, j.PrebuiltSrcs()...)
}
func (j *Import) IDECustomizedModuleName() string {
// TODO(b/113562217): Extract the base module name from the Import name, often the Import name
// has a prefix "prebuilt_". Remove the prefix explicitly if needed until we find a better
// solution to get the Import name.
name := j.Name()
if strings.HasPrefix(name, removedPrefix) {
name = strings.Trim(name, removedPrefix)
}
return name
}
var _ android.PrebuiltInterface = (*Import)(nil)
func ImportFactory() android.Module {
module := &Import{}
module.AddProperties(&module.properties)
android.InitPrebuiltModule(module, &module.properties.Jars)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
func ImportFactoryHost() android.Module {
module := &Import{}
module.AddProperties(&module.properties)
android.InitPrebuiltModule(module, &module.properties.Jars)
InitJavaModule(module, android.HostSupported)
return module
}
//
// Defaults
//
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
}
func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func defaultsFactory() android.Module {
return DefaultsFactory()
}
func DefaultsFactory(props ...interface{}) android.Module {
module := &Defaults{}
module.AddProperties(props...)
module.AddProperties(
&CompilerProperties{},
&CompilerDeviceProperties{},
&android.ProtoProperties{},
&aaptProperties{},
&androidLibraryProperties{},
&appProperties{},
&appTestProperties{},
&ImportProperties{},
&AARImportProperties{},
&sdkLibraryProperties{},
)
android.InitDefaultsModule(module)
return module
}
var Bool = proptools.Bool
var BoolDefault = proptools.BoolDefault
var String = proptools.String
var inList = android.InList