platform_build_soong/java/java.go
Colin Cross 43f08db29e Dexpreopt soong modules inside soong
Port the dexpreopt logic from Make to the dexpreopt package in Soong,
and use it to dexpreopt Soong modules.  The same package is also
compiled into the dexpreopt_gen binary to generate dexpreopt scripts
for Make modules.

This relands Ib67e2febf9ed921f06e8a86b9ec945c80dff35eb and
I462182638bd57b1367b5bfb0718e975c11ae66f7, along with multiple fixes
to depsfile generation in dexpreopt_gen that caused .odex files for
modules in defined make to be missing dependencies on boot.art, and
a fix to not dexpreopt and strip tests.

Bug: 119412419
Bug: 120273280
Test: no differences to dexpreopt outputs on aosp_sailfish system/,
      only expected changes to dexpreopt outputs on system_other
      (.vdex files for privileged Soong modules no longer incorrectly
      contain .dex contents).
Test: OUT_DIR=$PWD/out m
Test: NINJA_ARGS="-t deps out/target/product/sailfish/obj/APPS/Contacts_intermediates/dexpreopt.zip" m
Change-Id: I6bb2c971cee65d2338839753aa0d84939f335b1b
2018-12-15 19:07:54 -08:00

1917 lines
60 KiB
Go

// 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 module-specific flags that will be used for kotlinc compiles
Kotlincflags []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 not blank, set the targetSdkVersion in the AndroidManifest.xml.
// Defaults to sdk_version if not set.
Target_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
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
UncompressDex bool `blueprint:"mutated"`
IsSDKLibrary bool `blueprint:"mutated"`
}
// 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 that contains classes.dex if it should be in the output file
maybeStrippedDexJarFile 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
// manifest file to use instead of properties.Manifest
overrideManifest android.OptionalPath
// 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
dexpreopter
}
func (j *Module) Srcs() android.Paths {
return android.Paths{j.outputFile}
}
func (j *Module) DexJarFile() android.Path {
return j.dexJarFile
}
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"}
certificateTag = dependencyTag{name: "certificate"}
instrumentationForTag = dependencyTag{name: "instrumentation_for"}
)
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()
}
func (j *Module) targetSdkVersion() string {
if j.deviceProperties.Target_sdk_version != nil {
return *j.deviceProperties.Target_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
// targetSdkVersion returns the target_sdk_version property of the current module, or sdkVersion() if it is not set.
targetSdkVersion() string
}
func sdkVersionOrDefault(ctx android.BaseContext, v string) string {
switch v {
case "", "current", "system_current", "test_current", "core_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":
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{}
}
// 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", "")
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...)
ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
if !Bool(j.properties.No_framework_libs) {
ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
}
} else if sdkDep.useModule {
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?")
} 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) (ret linkType, stubs bool) {
ver := m.sdkVersion()
switch {
case name == "core.current.stubs" || name == "core.platform.api.stubs" ||
name == "stub-annotations" || name == "private-stub-annotations-jar" ||
name == "core-lambda-stubs":
return javaCore, true
case ver == "core_current":
return javaCore, false
case name == "android_system_stubs_current":
return javaSystem, true
case strings.HasPrefix(ver, "system_"):
return javaSystem, false
case name == "android_test_stubs_current":
return javaSystem, true
case strings.HasPrefix(ver, "test_"):
return javaPlatform, false
case name == "android_stubs_current":
return javaSdk, true
case ver == "current":
return javaSdk, false
case ver == "":
return javaPlatform, false
default:
if _, err := strconv.Atoi(ver); err != nil {
panic(fmt.Errorf("expected sdk_version to be a number, got %q", ver))
}
return javaSdk, false
}
}
func checkLinkType(ctx android.ModuleContext, from *Module, to *Library, tag dependencyTag) {
if ctx.Host() {
return
}
myLinkType, stubs := getLinkType(from, ctx.ModuleName())
if stubs {
return
}
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.collectAppDeps
return
}
if tag == certificateTag {
// Handled by AndroidApp.collectAppDeps
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, instrumentationForTag:
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:
linkType, _ := getLinkType(j, ctx.ModuleName())
deps.classpath = append(deps.classpath, dep.HeaderJars(linkType)...)
// 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
// javaVersion flag.
flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j))
// javac flags.
javacFlags := j.properties.Javacflags
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...)
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"))
}
}
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)
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") {
// user defined kotlin flags.
kotlincFlags := j.properties.Kotlincflags
CheckKotlincFlags(ctx, kotlincFlags)
// 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.
kotlincFlags = append(kotlincFlags, "-no-stdlib")
if ctx.Device() {
kotlincFlags = append(kotlincFlags, "-no-jdk")
}
if len(kotlincFlags) > 0 {
// optimization.
ctx.Variable(pctx, "kotlincFlags", strings.Join(kotlincFlags, " "))
flags.kotlincFlags += "$kotlincFlags"
}
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...)
manifest := j.overrideManifest
if !manifest.Valid() && 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
dexOutputFile = j.dexpreopt(ctx, dexOutputFile)
j.maybeStrippedDexJarFile = dexOutputFile
outputFile = dexOutputFile
if ctx.Failed() {
return
}
} 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()
}
// Check for invalid kotlinc flags. Only use this for flags explicitly passed by the user,
// since some of these flags may be used internally.
func CheckKotlincFlags(ctx android.ModuleContext, flags []string) {
for _, flag := range flags {
flag = strings.TrimSpace(flag)
if !strings.HasPrefix(flag, "-") {
ctx.PropertyErrorf("kotlincflags", "Flag `%s` must start with `-`", flag)
} else if strings.HasPrefix(flag, "-Xintellij-plugin-root") {
ctx.PropertyErrorf("kotlincflags",
"Bad flag: `%s`, only use internal compiler for consistency.", flag)
} else if inList(flag, config.KotlincIllegalFlags) {
ctx.PropertyErrorf("kotlincflags", "Flag `%s` already used by build system", flag)
} else if flag == "-include-runtime" {
ctx.PropertyErrorf("kotlincflags", "Bad flag: `%s`, do not include runtime.", flag)
} else {
args := strings.Split(flag, " ")
if args[0] == "-kotlin-home" {
ctx.PropertyErrorf("kotlincflags",
"Bad flag: `%s`, kotlin home already set to default (path to kotlinc in the repo).", flag)
}
}
}
}
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.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", ctx.ModuleName()+".jar")
j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
j.compile(ctx)
if Bool(j.properties.Installable) || ctx.Host() {
if j.deviceProperties.UncompressDex {
alignedOutputFile := android.PathForModuleOut(ctx, "aligned", ctx.ModuleName()+".jar")
TransformZipAlign(ctx, alignedOutputFile, j.outputFile)
j.outputFile = alignedOutputFile
}
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.dexpreoptProperties,
&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.dexpreoptProperties,
&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
// Name of the class containing main to be inserted into the manifest as Main-Class.
Main_class *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
if j.binaryProperties.Main_class != nil {
if j.properties.Manifest != nil {
ctx.PropertyErrorf("main_class", "main_class cannot be used when manifest is set")
}
manifestFile := android.PathForModuleOut(ctx, "manifest.txt")
GenerateMainClassManifest(ctx, manifestFile, String(j.binaryProperties.Main_class))
j.overrideManifest = android.OptionalPathForPath(manifestFile)
}
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.dexpreoptProperties,
&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.TrimPrefix(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{},
&DexpreoptProperties{},
&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