d788b3e6cb
Passing the list of all transitive aconfig files to Make causes extra Kati analysis runs when dependencies are changed in Android.bp files. Since Make is going to merge them anyways, merge them per-module and pass a single aconfig file to Make for each module. Fixes: 313698230 Test: m out/target/product/vsoc_x86_64/system/etc/aconfig_flags.pb Change-Id: Ifde4826bc93bc06e40338f72b4cb39eed26ca08d
2400 lines
89 KiB
Go
2400 lines
89 KiB
Go
// Copyright 2021 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
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"android/soong/ui/metrics/bp2build_metrics_proto"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/pathtools"
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
"android/soong/aconfig"
|
|
"android/soong/android"
|
|
"android/soong/dexpreopt"
|
|
"android/soong/java/config"
|
|
)
|
|
|
|
// This file contains the definition and the implementation of the base module that most
|
|
// source-based Java module structs embed.
|
|
|
|
// TODO:
|
|
// Autogenerated files:
|
|
// Renderscript
|
|
// Post-jar passes:
|
|
// Proguard
|
|
// Rmtypedefs
|
|
// DroidDoc
|
|
// Findbugs
|
|
|
|
// Properties that are common to most Java modules, i.e. whether it's a host or device module.
|
|
type CommonProperties struct {
|
|
// list of source files used to compile the Java module. May be .java, .kt, .logtags, .proto,
|
|
// or .aidl files.
|
|
Srcs []string `android:"path,arch_variant"`
|
|
|
|
// list Kotlin of source files containing Kotlin code that should be treated as common code in
|
|
// a codebase that supports Kotlin multiplatform. See
|
|
// https://kotlinlang.org/docs/reference/multiplatform.html. May be only be .kt files.
|
|
Common_srcs []string `android:"path,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:"path,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:"path,arch_variant"`
|
|
|
|
// list of files that should be excluded from java_resources and java_resource_dirs
|
|
Exclude_java_resources []string `android:"path,arch_variant"`
|
|
|
|
// 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 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"`
|
|
|
|
// list of java libraries that should not be used to build this module
|
|
Exclude_static_libs []string `android:"arch_variant"`
|
|
|
|
// manifest file to be included in resulting jar
|
|
Manifest *string `android:"path"`
|
|
|
|
// if not blank, run jarjar using the specified rules file
|
|
Jarjar_rules *string `android:"path,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
|
|
|
|
// If not empty, classes are restricted to the specified packages and their sub-packages.
|
|
// This restriction is checked after applying jarjar rules and including static libs.
|
|
Permitted_packages []string
|
|
|
|
// List of modules to use as annotation processors
|
|
Plugins []string
|
|
|
|
// List of modules to export to libraries that directly depend on this library as annotation
|
|
// processors. Note that if the plugins set generates_api: true this will disable the turbine
|
|
// optimization on modules that depend on this module, which will reduce parallelism and cause
|
|
// more recompilation.
|
|
Exported_plugins []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 or higher
|
|
Srcs []string `android:"path"`
|
|
|
|
// List of javac flags that should only be used when passing -source 1.9 or higher
|
|
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
|
|
|
|
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
|
|
|
|
// List of java_plugin modules that provide extra errorprone checks.
|
|
Extra_check_modules []string
|
|
|
|
// This property can be in 3 states. When set to true, errorprone will
|
|
// be run during the regular build. When set to false, errorprone will
|
|
// never be run. When unset, errorprone will be run when the RUN_ERROR_PRONE
|
|
// environment variable is true. Setting this to false will improve build
|
|
// performance more than adding -XepDisableAllChecks in javacflags.
|
|
Enabled *bool
|
|
}
|
|
|
|
Proto struct {
|
|
// List of extra options that will be passed to the proto generator.
|
|
Output_params []string
|
|
}
|
|
|
|
// If true, then jacocoagent is automatically added as a libs dependency so that
|
|
// r8 will not strip instrumentation classes out of dexed libraries.
|
|
Instrument bool `blueprint:"mutated"`
|
|
// If true, then the module supports statically including the jacocoagent
|
|
// into the library.
|
|
Supports_static_instrumentation bool `blueprint:"mutated"`
|
|
|
|
// List of files to include in the META-INF/services folder of the resulting jar.
|
|
Services []string `android:"path,arch_variant"`
|
|
|
|
// If true, package the kotlin stdlib into the jar. Defaults to true.
|
|
Static_kotlin_stdlib *bool `android:"arch_variant"`
|
|
|
|
// A list of java_library instances that provide additional hiddenapi annotations for the library.
|
|
Hiddenapi_additional_annotations []string
|
|
|
|
// Additional srcJars tacked in by GeneratedJavaLibraryModule
|
|
Generated_srcjars []android.Path `android:"mutated"`
|
|
|
|
// If true, then only the headers are built and not the implementation jar.
|
|
Headers_only *bool
|
|
}
|
|
|
|
// Properties that are specific to device modules. Host module factories should not add these when
|
|
// constructing a new module.
|
|
type DeviceProperties struct {
|
|
// If not blank, set to the version of the sdk to compile against.
|
|
// Defaults to an empty string, which compiles the module against the private platform APIs.
|
|
// Values are of one of the following forms:
|
|
// 1) numerical API level, "current", "none", or "core_platform"
|
|
// 2) An SDK kind with an API level: "<sdk kind>_<API level>"
|
|
// See build/soong/android/sdk_version.go for the complete and up to date list of SDK kinds.
|
|
// If the SDK kind is empty, it will be set to public.
|
|
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. See sdk_version for possible values.
|
|
Min_sdk_version *string
|
|
|
|
// if not blank, set the maximum version of the sdk that the compiled artifacts will run against.
|
|
// Defaults to empty string "". See sdk_version for possible values.
|
|
Max_sdk_version *string
|
|
|
|
// if not blank, set the maxSdkVersion properties of permission and uses-permission tags.
|
|
// Defaults to empty string "". See sdk_version for possible values.
|
|
Replace_max_sdk_version_placeholder *string
|
|
|
|
// if not blank, set the targetSdkVersion in the AndroidManifest.xml.
|
|
// Defaults to sdk_version if not set. See sdk_version for possible values.
|
|
Target_sdk_version *string
|
|
|
|
// Whether to compile against the platform APIs instead of an SDK.
|
|
// If true, then sdk_version must be empty. The value of this field
|
|
// is ignored when module's type isn't android_app, android_test, or android_test_helper_app.
|
|
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
|
|
|
|
// whether all interfaces should be annotated with required permissions.
|
|
Enforce_permissions *bool
|
|
|
|
// allowlist for interfaces that (temporarily) do not require annotation for permissions.
|
|
Enforce_permissions_exceptions []string `android:"path"`
|
|
|
|
// list of flags that will be passed to the AIDL compiler
|
|
Flags []string
|
|
}
|
|
|
|
// If true, export a copy of the module as a -hostdex module for host testing.
|
|
Hostdex *bool
|
|
|
|
Target struct {
|
|
Hostdex struct {
|
|
// Additional required dependencies to add to -hostdex modules.
|
|
Required []string
|
|
}
|
|
}
|
|
|
|
// When targeting 1.9 and above, override the modules to use with --system,
|
|
// otherwise provides defaults libraries to add to the bootclasspath.
|
|
System_modules *string
|
|
|
|
IsSDKLibrary bool `blueprint:"mutated"`
|
|
|
|
// If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file.
|
|
// Defaults to false.
|
|
V4_signature *bool
|
|
|
|
// Only for libraries created by a sysprop_library module, SyspropPublicStub is the name of the
|
|
// public stubs library.
|
|
SyspropPublicStub string `blueprint:"mutated"`
|
|
|
|
HiddenAPIPackageProperties
|
|
HiddenAPIFlagFileProperties
|
|
}
|
|
|
|
// Device properties that can be overridden by overriding module (e.g. override_android_app)
|
|
type OverridableDeviceProperties struct {
|
|
// set the name of the output. If not set, `name` is used.
|
|
// To override a module with this property set, overriding module might need to set this as well.
|
|
// Otherwise, both the overridden and the overriding modules will have the same output name, which
|
|
// can cause the duplicate output error.
|
|
Stem *string
|
|
}
|
|
|
|
// Functionality common to Module and Import
|
|
//
|
|
// It is embedded in Module so its functionality can be used by methods in Module
|
|
// but it is currently only initialized by Import and Library.
|
|
type embeddableInModuleAndImport struct {
|
|
|
|
// Functionality related to this being used as a component of a java_sdk_library.
|
|
EmbeddableSdkLibraryComponent
|
|
}
|
|
|
|
func (e *embeddableInModuleAndImport) initModuleAndImport(module android.Module) {
|
|
e.initSdkLibraryComponent(module)
|
|
}
|
|
|
|
// Module/Import's DepIsInSameApex(...) delegates to this method.
|
|
//
|
|
// This cannot implement DepIsInSameApex(...) directly as that leads to ambiguity with
|
|
// the one provided by ApexModuleBase.
|
|
func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
|
|
// dependencies other than the static linkage are all considered crossing APEX boundary
|
|
if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// OptionalDexJarPath can be either unset, hold a valid path to a dex jar file,
|
|
// or an invalid path describing the reason it is invalid.
|
|
//
|
|
// It is unset if a dex jar isn't applicable, i.e. no build rule has been
|
|
// requested to create one.
|
|
//
|
|
// If a dex jar has been requested to be built then it is set, and it may be
|
|
// either a valid android.Path, or invalid with a reason message. The latter
|
|
// happens if the source that should produce the dex file isn't able to.
|
|
//
|
|
// E.g. it is invalid with a reason message if there is a prebuilt APEX that
|
|
// could produce the dex jar through a deapexer module, but the APEX isn't
|
|
// installable so doing so wouldn't be safe.
|
|
type OptionalDexJarPath struct {
|
|
isSet bool
|
|
path android.OptionalPath
|
|
}
|
|
|
|
// IsSet returns true if a path has been set, either invalid or valid.
|
|
func (o OptionalDexJarPath) IsSet() bool {
|
|
return o.isSet
|
|
}
|
|
|
|
// Valid returns true if there is a path that is valid.
|
|
func (o OptionalDexJarPath) Valid() bool {
|
|
return o.isSet && o.path.Valid()
|
|
}
|
|
|
|
// Path returns the valid path, or panics if it's either not set or is invalid.
|
|
func (o OptionalDexJarPath) Path() android.Path {
|
|
if !o.isSet {
|
|
panic("path isn't set")
|
|
}
|
|
return o.path.Path()
|
|
}
|
|
|
|
// PathOrNil returns the path if it's set and valid, or else nil.
|
|
func (o OptionalDexJarPath) PathOrNil() android.Path {
|
|
if o.Valid() {
|
|
return o.Path()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// InvalidReason returns the reason for an invalid path, which is never "". It
|
|
// returns "" for an unset or valid path.
|
|
func (o OptionalDexJarPath) InvalidReason() string {
|
|
if !o.isSet {
|
|
return ""
|
|
}
|
|
return o.path.InvalidReason()
|
|
}
|
|
|
|
func (o OptionalDexJarPath) String() string {
|
|
if !o.isSet {
|
|
return "<unset>"
|
|
}
|
|
return o.path.String()
|
|
}
|
|
|
|
// makeUnsetDexJarPath returns an unset OptionalDexJarPath.
|
|
func makeUnsetDexJarPath() OptionalDexJarPath {
|
|
return OptionalDexJarPath{isSet: false}
|
|
}
|
|
|
|
// makeDexJarPathFromOptionalPath returns an OptionalDexJarPath that is set with
|
|
// the given OptionalPath, which may be valid or invalid.
|
|
func makeDexJarPathFromOptionalPath(path android.OptionalPath) OptionalDexJarPath {
|
|
return OptionalDexJarPath{isSet: true, path: path}
|
|
}
|
|
|
|
// makeDexJarPathFromPath returns an OptionalDexJarPath that is set with the
|
|
// valid given path. It returns an unset OptionalDexJarPath if the given path is
|
|
// nil.
|
|
func makeDexJarPathFromPath(path android.Path) OptionalDexJarPath {
|
|
if path == nil {
|
|
return makeUnsetDexJarPath()
|
|
}
|
|
return makeDexJarPathFromOptionalPath(android.OptionalPathForPath(path))
|
|
}
|
|
|
|
// Module contains the properties and members used by all java module types
|
|
type Module struct {
|
|
android.ModuleBase
|
|
android.DefaultableModuleBase
|
|
android.ApexModuleBase
|
|
android.BazelModuleBase
|
|
|
|
// Functionality common to Module and Import.
|
|
embeddableInModuleAndImport
|
|
|
|
properties CommonProperties
|
|
protoProperties android.ProtoProperties
|
|
deviceProperties DeviceProperties
|
|
|
|
overridableDeviceProperties OverridableDeviceProperties
|
|
|
|
// 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
|
|
|
|
// args and dependencies to package source files into a srcjar
|
|
srcJarArgs []string
|
|
srcJarDeps android.Paths
|
|
|
|
// the source files of this module and all its static dependencies
|
|
transitiveSrcFiles *android.DepSet[android.Path]
|
|
|
|
// jar file containing implementation classes and resources including static library
|
|
// dependencies
|
|
implementationAndResourcesJar android.Path
|
|
|
|
// output file containing classes.dex and resources
|
|
dexJarFile OptionalDexJarPath
|
|
|
|
// output file containing uninstrumented classes that will be instrumented by jacoco
|
|
jacocoReportClassesFile android.Path
|
|
|
|
// output file of the module, which may be a classes jar or a dex jar
|
|
outputFile android.Path
|
|
extraOutputFiles android.Paths
|
|
|
|
exportAidlIncludeDirs android.Paths
|
|
ignoredAidlPermissionList android.Paths
|
|
|
|
logtagsSrcs android.Paths
|
|
|
|
// installed file for binary dependency
|
|
installFile android.Path
|
|
|
|
// installed file for hostdex copy
|
|
hostdexInstallFile android.InstallPath
|
|
|
|
// list of unique .java and .kt source files
|
|
uniqueSrcFiles android.Paths
|
|
|
|
// list of srcjars that was passed to javac
|
|
compiledSrcJars android.Paths
|
|
|
|
// manifest file to use instead of properties.Manifest
|
|
overrideManifest android.OptionalPath
|
|
|
|
// list of plugins that this java module is exporting
|
|
exportedPluginJars android.Paths
|
|
|
|
// list of plugins that this java module is exporting
|
|
exportedPluginClasses []string
|
|
|
|
// if true, the exported plugins generate API and require disabling turbine.
|
|
exportedDisableTurbine bool
|
|
|
|
// list of source files, collected from srcFiles with unique java and all kt files,
|
|
// will be used by android.IDEInfo struct
|
|
expandIDEInfoCompiledSrcs []string
|
|
|
|
// expanded Jarjar_rules
|
|
expandJarjarRules android.Path
|
|
|
|
// Extra files generated by the module type to be added as java resources.
|
|
extraResources android.Paths
|
|
|
|
hiddenAPI
|
|
dexer
|
|
dexpreopter
|
|
usesLibrary
|
|
linter
|
|
|
|
// list of the xref extraction files
|
|
kytheFiles android.Paths
|
|
|
|
hideApexVariantFromMake bool
|
|
|
|
sdkVersion android.SdkSpec
|
|
minSdkVersion android.ApiLevel
|
|
maxSdkVersion android.ApiLevel
|
|
|
|
sourceExtensions []string
|
|
|
|
annoSrcJars android.Paths
|
|
|
|
// output file name based on Stem property.
|
|
// This should be set in every ModuleWithStem's GenerateAndroidBuildActions
|
|
// or the module should override Stem().
|
|
stem string
|
|
|
|
// Single aconfig "cache file" merged from this module and all dependencies.
|
|
mergedAconfigFiles map[string]android.Paths
|
|
}
|
|
|
|
func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
|
|
sdkVersion := j.SdkVersion(ctx)
|
|
if sdkVersion.Stable() {
|
|
return nil
|
|
}
|
|
if sdkVersion.Kind == android.SdkCorePlatform {
|
|
if useLegacyCorePlatformApi(ctx, j.BaseModuleName()) {
|
|
return fmt.Errorf("non stable SDK %v - uses legacy core platform", sdkVersion)
|
|
} else {
|
|
// Treat stable core platform as stable.
|
|
return nil
|
|
}
|
|
} else {
|
|
return fmt.Errorf("non stable SDK %v", sdkVersion)
|
|
}
|
|
}
|
|
|
|
// checkSdkVersions enforces restrictions around SDK dependencies.
|
|
func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
|
|
if j.RequiresStableAPIs(ctx) {
|
|
if sc, ok := ctx.Module().(android.SdkContext); ok {
|
|
if !sc.SdkVersion(ctx).Specified() {
|
|
ctx.PropertyErrorf("sdk_version",
|
|
"sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).")
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make sure this module doesn't statically link to modules with lower-ranked SDK link type.
|
|
// See rank() for details.
|
|
ctx.VisitDirectDeps(func(module android.Module) {
|
|
tag := ctx.OtherModuleDependencyTag(module)
|
|
switch module.(type) {
|
|
// TODO(satayev): cover other types as well, e.g. imports
|
|
case *Library, *AndroidLibrary:
|
|
switch tag {
|
|
case bootClasspathTag, sdkLibTag, libTag, staticLibTag, java9LibTag:
|
|
j.checkSdkLinkType(ctx, module.(moduleWithSdkDep), tag.(dependencyTag))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
|
|
if sc, ok := ctx.Module().(android.SdkContext); ok {
|
|
usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
|
|
sdkVersionSpecified := sc.SdkVersion(ctx).Specified()
|
|
if usePlatformAPI && sdkVersionSpecified {
|
|
ctx.PropertyErrorf("platform_apis", "This module has conflicting settings. sdk_version is not empty, which means this module cannot use platform APIs. However platform_apis is set to true.")
|
|
} else if !usePlatformAPI && !sdkVersionSpecified {
|
|
ctx.PropertyErrorf("platform_apis", "This module has conflicting settings. sdk_version is empty, which means that this module is build against platform APIs. However platform_apis is not set to true")
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func (j *Module) checkHeadersOnly(ctx android.ModuleContext) {
|
|
if _, ok := ctx.Module().(android.SdkContext); ok {
|
|
headersOnly := proptools.Bool(j.properties.Headers_only)
|
|
installable := proptools.Bool(j.properties.Installable)
|
|
|
|
if headersOnly && installable {
|
|
ctx.PropertyErrorf("headers_only", "This module has conflicting settings. headers_only is true which, which means this module doesn't generate an implementation jar. However installable is set to true.")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (j *Module) addHostProperties() {
|
|
j.AddProperties(
|
|
&j.properties,
|
|
&j.protoProperties,
|
|
&j.usesLibraryProperties,
|
|
)
|
|
}
|
|
|
|
func (j *Module) addHostAndDeviceProperties() {
|
|
j.addHostProperties()
|
|
j.AddProperties(
|
|
&j.deviceProperties,
|
|
&j.overridableDeviceProperties,
|
|
&j.dexer.dexProperties,
|
|
&j.dexpreoptProperties,
|
|
&j.linter.properties,
|
|
)
|
|
}
|
|
|
|
// provideHiddenAPIPropertyInfo populates a HiddenAPIPropertyInfo from hidden API properties and
|
|
// makes it available through the hiddenAPIPropertyInfoProvider.
|
|
func (j *Module) provideHiddenAPIPropertyInfo(ctx android.ModuleContext) {
|
|
hiddenAPIInfo := newHiddenAPIPropertyInfo()
|
|
|
|
// Populate with flag file paths from the properties.
|
|
hiddenAPIInfo.extractFlagFilesFromProperties(ctx, &j.deviceProperties.HiddenAPIFlagFileProperties)
|
|
|
|
// Populate with package rules from the properties.
|
|
hiddenAPIInfo.extractPackageRulesFromProperties(&j.deviceProperties.HiddenAPIPackageProperties)
|
|
|
|
ctx.SetProvider(hiddenAPIPropertyInfoProvider, hiddenAPIInfo)
|
|
}
|
|
|
|
func (j *Module) OutputFiles(tag string) (android.Paths, error) {
|
|
switch tag {
|
|
case "":
|
|
return append(android.Paths{j.outputFile}, j.extraOutputFiles...), nil
|
|
case android.DefaultDistTag:
|
|
return android.Paths{j.outputFile}, nil
|
|
case ".jar":
|
|
return android.Paths{j.implementationAndResourcesJar}, nil
|
|
case ".hjar":
|
|
return android.Paths{j.headerJarFile}, nil
|
|
case ".proguard_map":
|
|
if j.dexer.proguardDictionary.Valid() {
|
|
return android.Paths{j.dexer.proguardDictionary.Path()}, nil
|
|
}
|
|
return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
|
|
case ".generated_srcjars":
|
|
return j.properties.Generated_srcjars, nil
|
|
case ".lint":
|
|
if j.linter.outputs.xml != nil {
|
|
return android.Paths{j.linter.outputs.xml}, nil
|
|
}
|
|
return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
|
}
|
|
}
|
|
|
|
var _ android.OutputFileProducer = (*Module)(nil)
|
|
|
|
func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
|
|
initJavaModule(module, hod, false)
|
|
}
|
|
|
|
func InitJavaModuleMultiTargets(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
|
|
initJavaModule(module, hod, true)
|
|
}
|
|
|
|
func initJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported, multiTargets bool) {
|
|
multilib := android.MultilibCommon
|
|
if multiTargets {
|
|
android.InitAndroidMultiTargetsArchModule(module, hod, multilib)
|
|
} else {
|
|
android.InitAndroidArchModule(module, hod, multilib)
|
|
}
|
|
android.InitDefaultableModule(module)
|
|
}
|
|
|
|
func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool {
|
|
return j.properties.Instrument &&
|
|
ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") &&
|
|
ctx.DeviceConfig().JavaCoverageEnabledForPath(ctx.ModuleDir())
|
|
}
|
|
|
|
func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool {
|
|
return j.properties.Supports_static_instrumentation &&
|
|
j.shouldInstrument(ctx) &&
|
|
(ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_STATIC") ||
|
|
ctx.Config().UnbundledBuild())
|
|
}
|
|
|
|
func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool {
|
|
// Force enable the instrumentation for java code that is built for APEXes ...
|
|
// except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
|
|
// doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true.
|
|
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
|
|
isJacocoAgent := ctx.ModuleName() == "jacocoagent"
|
|
if j.DirectlyInAnyApex() && !isJacocoAgent && !apexInfo.IsForPlatform() {
|
|
if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
|
|
return true
|
|
} else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (j *Module) setInstrument(value bool) {
|
|
j.properties.Instrument = value
|
|
}
|
|
|
|
func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
|
|
return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version))
|
|
}
|
|
|
|
func (j *Module) SystemModules() string {
|
|
return proptools.String(j.deviceProperties.System_modules)
|
|
}
|
|
|
|
func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
|
|
if j.deviceProperties.Min_sdk_version != nil {
|
|
return android.ApiLevelFrom(ctx, *j.deviceProperties.Min_sdk_version)
|
|
}
|
|
return j.SdkVersion(ctx).ApiLevel
|
|
}
|
|
|
|
func (j *Module) GetDeviceProperties() *DeviceProperties {
|
|
return &j.deviceProperties
|
|
}
|
|
|
|
func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
|
|
if j.deviceProperties.Max_sdk_version != nil {
|
|
return android.ApiLevelFrom(ctx, *j.deviceProperties.Max_sdk_version)
|
|
}
|
|
// Default is PrivateApiLevel
|
|
return android.SdkSpecPrivate.ApiLevel
|
|
}
|
|
|
|
func (j *Module) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel {
|
|
if j.deviceProperties.Replace_max_sdk_version_placeholder != nil {
|
|
return android.ApiLevelFrom(ctx, *j.deviceProperties.Replace_max_sdk_version_placeholder)
|
|
}
|
|
// Default is PrivateApiLevel
|
|
return android.SdkSpecPrivate.ApiLevel
|
|
}
|
|
|
|
func (j *Module) MinSdkVersionString() string {
|
|
return j.minSdkVersion.String()
|
|
}
|
|
|
|
func (j *Module) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
|
|
if j.deviceProperties.Target_sdk_version != nil {
|
|
return android.ApiLevelFrom(ctx, *j.deviceProperties.Target_sdk_version)
|
|
}
|
|
return j.SdkVersion(ctx).ApiLevel
|
|
}
|
|
|
|
func (j *Module) AvailableFor(what string) bool {
|
|
if what == android.AvailableToPlatform && Bool(j.deviceProperties.Hostdex) {
|
|
// Exception: for hostdex: true libraries, the platform variant is created
|
|
// even if it's not marked as available to platform. In that case, the platform
|
|
// variant is used only for the hostdex and not installed to the device.
|
|
return true
|
|
}
|
|
return j.ApexModuleBase.AvailableFor(what)
|
|
}
|
|
|
|
func (j *Module) deps(ctx android.BottomUpMutatorContext) {
|
|
if ctx.Device() {
|
|
j.linter.deps(ctx)
|
|
|
|
sdkDeps(ctx, android.SdkContext(j), j.dexer)
|
|
|
|
if j.deviceProperties.SyspropPublicStub != "" {
|
|
// This is a sysprop implementation library that has a corresponding sysprop public
|
|
// stubs library, and a dependency on it so that dependencies on the implementation can
|
|
// be forwarded to the public stubs library when necessary.
|
|
ctx.AddVariationDependencies(nil, syspropPublicStubDepTag, j.deviceProperties.SyspropPublicStub)
|
|
}
|
|
}
|
|
|
|
libDeps := ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
|
|
|
|
j.properties.Static_libs = android.RemoveListFromList(j.properties.Static_libs, j.properties.Exclude_static_libs)
|
|
ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
|
|
|
|
// Add dependency on libraries that provide additional hidden api annotations.
|
|
ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
|
|
|
|
if ctx.DeviceConfig().VndkVersion() != "" && ctx.Config().EnforceInterPartitionJavaSdkLibrary() {
|
|
// Require java_sdk_library at inter-partition java dependency to ensure stable
|
|
// interface between partitions. If inter-partition java_library dependency is detected,
|
|
// raise build error because java_library doesn't have a stable interface.
|
|
//
|
|
// Inputs:
|
|
// PRODUCT_ENFORCE_INTER_PARTITION_JAVA_SDK_LIBRARY
|
|
// if true, enable enforcement
|
|
// PRODUCT_INTER_PARTITION_JAVA_LIBRARY_ALLOWLIST
|
|
// exception list of java_library names to allow inter-partition dependency
|
|
for idx := range j.properties.Libs {
|
|
if libDeps[idx] == nil {
|
|
continue
|
|
}
|
|
|
|
if javaDep, ok := libDeps[idx].(javaSdkLibraryEnforceContext); ok {
|
|
// java_sdk_library is always allowed at inter-partition dependency.
|
|
// So, skip check.
|
|
if _, ok := javaDep.(*SdkLibrary); ok {
|
|
continue
|
|
}
|
|
|
|
j.checkPartitionsForJavaDependency(ctx, "libs", javaDep)
|
|
}
|
|
}
|
|
}
|
|
|
|
// For library dependencies that are component libraries (like stubs), add the implementation
|
|
// as a dependency (dexpreopt needs to be against the implementation library, not stubs).
|
|
for _, dep := range libDeps {
|
|
if dep != nil {
|
|
if component, ok := dep.(SdkLibraryComponentDependency); ok {
|
|
if lib := component.OptionalSdkLibraryImplementation(); lib != nil {
|
|
// Add library as optional if it's one of the optional compatibility libs.
|
|
tag := usesLibReqTag
|
|
if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) {
|
|
tag = usesLibOptTag
|
|
}
|
|
ctx.AddVariationDependencies(nil, tag, *lib)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...)
|
|
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), errorpronePluginTag, j.properties.Errorprone.Extra_check_modules...)
|
|
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), exportedPluginTag, j.properties.Exported_plugins...)
|
|
|
|
android.ProtoDeps(ctx, &j.protoProperties)
|
|
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", "kotlin-stdlib-jdk7", "kotlin-stdlib-jdk8")
|
|
ctx.AddVariationDependencies(nil, kotlinAnnotationsTag, "kotlin-annotations")
|
|
}
|
|
|
|
// Framework libraries need special handling in static coverage builds: they should not have
|
|
// static dependency on jacoco, otherwise there would be multiple conflicting definitions of
|
|
// the same jacoco classes coming from different bootclasspath jars.
|
|
if inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
|
|
if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
|
|
j.properties.Instrument = true
|
|
}
|
|
} else if j.shouldInstrumentStatic(ctx) {
|
|
ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent")
|
|
}
|
|
|
|
if j.useCompose() {
|
|
ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag,
|
|
"androidx.compose.compiler_compiler-hosted")
|
|
}
|
|
}
|
|
|
|
func hasSrcExt(srcs []string, ext string) bool {
|
|
for _, src := range srcs {
|
|
if filepath.Ext(src) == ext {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (j *Module) hasSrcExt(ext string) bool {
|
|
return hasSrcExt(j.properties.Srcs, ext)
|
|
}
|
|
|
|
func (j *Module) individualAidlFlags(ctx android.ModuleContext, aidlFile android.Path) string {
|
|
var flags string
|
|
|
|
if Bool(j.deviceProperties.Aidl.Enforce_permissions) {
|
|
if !android.InList(aidlFile.String(), j.ignoredAidlPermissionList.Strings()) {
|
|
flags = "-Wmissing-permission-annotation -Werror"
|
|
}
|
|
}
|
|
return flags
|
|
}
|
|
|
|
func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
|
|
aidlIncludeDirs android.Paths, aidlSrcs android.Paths) (string, android.Paths) {
|
|
|
|
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)...)
|
|
|
|
var flags []string
|
|
var deps android.Paths
|
|
var includeDirs android.Paths
|
|
|
|
flags = append(flags, j.deviceProperties.Aidl.Flags...)
|
|
|
|
if aidlPreprocess.Valid() {
|
|
flags = append(flags, "-p"+aidlPreprocess.String())
|
|
deps = append(deps, aidlPreprocess.Path())
|
|
} else if len(aidlIncludeDirs) > 0 {
|
|
includeDirs = append(includeDirs, aidlIncludeDirs...)
|
|
}
|
|
|
|
if len(j.exportAidlIncludeDirs) > 0 {
|
|
includeDirs = append(includeDirs, j.exportAidlIncludeDirs...)
|
|
}
|
|
|
|
if len(aidlIncludes) > 0 {
|
|
includeDirs = append(includeDirs, aidlIncludes...)
|
|
}
|
|
|
|
includeDirs = append(includeDirs, android.PathForModuleSrc(ctx))
|
|
if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() {
|
|
includeDirs = append(includeDirs, src.Path())
|
|
}
|
|
flags = append(flags, android.JoinWithPrefix(includeDirs.Strings(), "-I"))
|
|
// add flags for dirs containing AIDL srcs that haven't been specified yet
|
|
flags = append(flags, genAidlIncludeFlags(ctx, aidlSrcs, includeDirs))
|
|
|
|
sdkVersion := (j.SdkVersion(ctx)).Kind
|
|
defaultTrace := ((sdkVersion == android.SdkSystemServer) || (sdkVersion == android.SdkCore) || (sdkVersion == android.SdkCorePlatform) || (sdkVersion == android.SdkModule) || (sdkVersion == android.SdkSystem))
|
|
if proptools.BoolDefault(j.deviceProperties.Aidl.Generate_traces, defaultTrace) {
|
|
flags = append(flags, "-t")
|
|
}
|
|
|
|
if Bool(j.deviceProperties.Aidl.Generate_get_transaction_name) {
|
|
flags = append(flags, "--transaction_names")
|
|
}
|
|
|
|
if Bool(j.deviceProperties.Aidl.Enforce_permissions) {
|
|
exceptions := j.deviceProperties.Aidl.Enforce_permissions_exceptions
|
|
j.ignoredAidlPermissionList = android.PathsForModuleSrcExcludes(ctx, exceptions, nil)
|
|
}
|
|
|
|
aidlMinSdkVersion := j.MinSdkVersion(ctx).String()
|
|
flags = append(flags, "--min_sdk_version="+aidlMinSdkVersion)
|
|
|
|
return strings.Join(flags, " "), deps
|
|
}
|
|
|
|
func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaBuilderFlags {
|
|
|
|
var flags javaBuilderFlags
|
|
|
|
// javaVersion flag.
|
|
flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), android.SdkContext(j))
|
|
|
|
epEnabled := j.properties.Errorprone.Enabled
|
|
if (ctx.Config().RunErrorProne() && epEnabled == nil) || Bool(epEnabled) {
|
|
if config.ErrorProneClasspath == nil && !ctx.Config().RunningInsideUnitTest() {
|
|
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.ErrorProneHeapFlags} ${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.dexClasspath = append(flags.dexClasspath, deps.dexClasspath...)
|
|
flags.java9Classpath = append(flags.java9Classpath, deps.java9Classpath...)
|
|
flags.processorPath = append(flags.processorPath, deps.processorPath...)
|
|
flags.errorProneProcessorPath = append(flags.errorProneProcessorPath, deps.errorProneProcessorPath...)
|
|
|
|
flags.processors = append(flags.processors, deps.processorClasses...)
|
|
flags.processors = android.FirstUniqueStrings(flags.processors)
|
|
|
|
if len(flags.bootClasspath) == 0 && ctx.Host() && !flags.javaVersion.usesJavaModules() &&
|
|
decodeSdkDep(ctx, android.SdkContext(j)).hasStandardLibs() {
|
|
// 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"))
|
|
}
|
|
}
|
|
|
|
// systemModules
|
|
flags.systemModules = deps.systemModules
|
|
|
|
return flags
|
|
}
|
|
|
|
func (j *Module) collectJavacFlags(
|
|
ctx android.ModuleContext, flags javaBuilderFlags, srcFiles android.Paths) javaBuilderFlags {
|
|
// javac flags.
|
|
javacFlags := j.properties.Javacflags
|
|
var needsDebugInfo bool
|
|
|
|
needsDebugInfo = false
|
|
for _, flag := range javacFlags {
|
|
if strings.HasPrefix(flag, "-g") {
|
|
needsDebugInfo = true
|
|
}
|
|
}
|
|
|
|
if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() && !needsDebugInfo {
|
|
// For non-host binaries, override the -g flag passed globally to remove
|
|
// local variable debug info to reduce disk and memory usage.
|
|
javacFlags = append(javacFlags, "-g:source,lines")
|
|
}
|
|
javacFlags = append(javacFlags, "-Xlint:-dep-ann")
|
|
|
|
if flags.javaVersion.usesJavaModules() {
|
|
javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
|
|
} else if len(j.properties.Openjdk9.Javacflags) > 0 {
|
|
// java version defaults higher than openjdk 9, these conditionals should no longer be necessary
|
|
ctx.PropertyErrorf("openjdk9.javacflags", "JDK version defaults to higher than 9")
|
|
}
|
|
|
|
if flags.javaVersion.usesJavaModules() {
|
|
if j.properties.Patch_module != nil {
|
|
// Manually specify build directory in case it is not under the repo root.
|
|
// (javac doesn't seem to expand into symbolic links when searching for patch-module targets, so
|
|
// just adding a symlink under the root doesn't help.)
|
|
patchPaths := []string{".", ctx.Config().SoongOutDir()}
|
|
|
|
// b/150878007
|
|
//
|
|
// Workaround to support *Bazel-executed* JDK9 javac in Bazel's
|
|
// execution root for --patch-module. If this javac command line is
|
|
// invoked within Bazel's execution root working directory, the top
|
|
// level directories (e.g. libcore/, tools/, frameworks/) are all
|
|
// symlinks. JDK9 javac does not traverse into symlinks, which causes
|
|
// --patch-module to fail source file lookups when invoked in the
|
|
// execution root.
|
|
//
|
|
// Short of patching javac or enumerating *all* directories as possible
|
|
// input dirs, manually add the top level dir of the source files to be
|
|
// compiled.
|
|
topLevelDirs := map[string]bool{}
|
|
for _, srcFilePath := range srcFiles {
|
|
srcFileParts := strings.Split(srcFilePath.String(), "/")
|
|
// Ignore source files that are already in the top level directory
|
|
// as well as generated files in the out directory. The out
|
|
// directory may be an absolute path, which means srcFileParts[0] is the
|
|
// empty string, so check that as well. Note that "out" in Bazel's execution
|
|
// root is *not* a symlink, which doesn't cause problems for --patch-modules
|
|
// anyway, so it's fine to not apply this workaround for generated
|
|
// source files.
|
|
if len(srcFileParts) > 1 &&
|
|
srcFileParts[0] != "" &&
|
|
srcFileParts[0] != "out" {
|
|
topLevelDirs[srcFileParts[0]] = true
|
|
}
|
|
}
|
|
patchPaths = append(patchPaths, android.SortedKeys(topLevelDirs)...)
|
|
|
|
classPath := flags.classpath.FormJavaClassPath("")
|
|
if classPath != "" {
|
|
patchPaths = append(patchPaths, classPath)
|
|
}
|
|
javacFlags = append(
|
|
javacFlags,
|
|
"--patch-module="+String(j.properties.Patch_module)+"="+strings.Join(patchPaths, ":"))
|
|
}
|
|
}
|
|
|
|
if len(javacFlags) > 0 {
|
|
// optimization.
|
|
ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
|
|
flags.javacFlags = "$javacFlags"
|
|
}
|
|
|
|
return flags
|
|
}
|
|
|
|
func (j *Module) AddJSONData(d *map[string]interface{}) {
|
|
(&j.ModuleBase).AddJSONData(d)
|
|
(*d)["Java"] = map[string]interface{}{
|
|
"SourceExtensions": j.sourceExtensions,
|
|
}
|
|
|
|
}
|
|
|
|
func (j *Module) addGeneratedSrcJars(path android.Path) {
|
|
j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path)
|
|
}
|
|
|
|
func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
|
|
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
|
|
|
|
deps := j.collectDeps(ctx)
|
|
flags := j.collectBuilderFlags(ctx, deps)
|
|
|
|
if flags.javaVersion.usesJavaModules() {
|
|
j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
|
|
} else if len(j.properties.Openjdk9.Javacflags) > 0 {
|
|
// java version defaults higher than openjdk 9, these conditionals should no longer be necessary
|
|
ctx.PropertyErrorf("openjdk9.srcs", "JDK version defaults to higher than 9")
|
|
}
|
|
|
|
srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
|
|
j.sourceExtensions = []string{}
|
|
for _, ext := range []string{".kt", ".proto", ".aidl", ".java", ".logtags"} {
|
|
if hasSrcExt(srcFiles.Strings(), ext) {
|
|
j.sourceExtensions = append(j.sourceExtensions, ext)
|
|
}
|
|
}
|
|
if hasSrcExt(srcFiles.Strings(), ".proto") {
|
|
flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
|
|
}
|
|
|
|
kotlinCommonSrcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Common_srcs, nil)
|
|
if len(kotlinCommonSrcFiles.FilterOutByExt(".kt")) > 0 {
|
|
ctx.PropertyErrorf("common_srcs", "common_srcs must be .kt files")
|
|
}
|
|
|
|
aidlSrcs := srcFiles.FilterByExt(".aidl")
|
|
flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs, aidlSrcs)
|
|
|
|
nonGeneratedSrcJars := srcFiles.FilterByExt(".srcjar")
|
|
srcFiles = j.genSources(ctx, srcFiles, flags)
|
|
|
|
// Collect javac flags only after computing the full set of srcFiles to
|
|
// ensure that the --patch-module lookup paths are complete.
|
|
flags = j.collectJavacFlags(ctx, flags, srcFiles)
|
|
|
|
srcJars := srcFiles.FilterByExt(".srcjar")
|
|
srcJars = append(srcJars, deps.srcJars...)
|
|
srcJars = append(srcJars, extraSrcJars...)
|
|
srcJars = append(srcJars, j.properties.Generated_srcjars...)
|
|
srcFiles = srcFiles.FilterOutByExt(".srcjar")
|
|
|
|
if j.properties.Jarjar_rules != nil {
|
|
j.expandJarjarRules = android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
|
|
}
|
|
|
|
jarName := j.Stem() + ".jar"
|
|
|
|
var uniqueJavaFiles android.Paths
|
|
set := make(map[string]bool)
|
|
for _, v := range srcFiles.FilterByExt(".java") {
|
|
if _, found := set[v.String()]; !found {
|
|
set[v.String()] = true
|
|
uniqueJavaFiles = append(uniqueJavaFiles, v)
|
|
}
|
|
}
|
|
var uniqueKtFiles android.Paths
|
|
for _, v := range srcFiles.FilterByExt(".kt") {
|
|
if _, found := set[v.String()]; !found {
|
|
set[v.String()] = true
|
|
uniqueKtFiles = append(uniqueKtFiles, v)
|
|
}
|
|
}
|
|
|
|
var uniqueSrcFiles android.Paths
|
|
uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...)
|
|
uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...)
|
|
j.uniqueSrcFiles = uniqueSrcFiles
|
|
ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: uniqueSrcFiles.Strings()})
|
|
|
|
// We don't currently run annotation processors in turbine, which means we can't use turbine
|
|
// generated header jars when an annotation processor that generates API is enabled. One
|
|
// exception (handled further below) is when kotlin sources are enabled, in which case turbine
|
|
// is used to run all of the annotation processors.
|
|
disableTurbine := deps.disableTurbine
|
|
|
|
// Collect .java and .kt files for AIDEGen
|
|
j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, uniqueSrcFiles.Strings()...)
|
|
|
|
var kotlinJars android.Paths
|
|
var kotlinHeaderJars android.Paths
|
|
|
|
// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
|
|
// any dependencies so that it can override any non-final R classes from dependencies with the
|
|
// final R classes from the app.
|
|
flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...)
|
|
|
|
// If compiling headers then compile them and skip the rest
|
|
if proptools.Bool(j.properties.Headers_only) {
|
|
if srcFiles.HasExt(".kt") {
|
|
ctx.ModuleErrorf("Compiling headers_only with .kt not supported")
|
|
}
|
|
if ctx.Config().IsEnvFalse("TURBINE_ENABLED") || disableTurbine {
|
|
ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.")
|
|
}
|
|
|
|
_, j.headerJarFile =
|
|
j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
|
|
extraCombinedJars)
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
|
|
ctx.SetProvider(JavaInfoProvider, JavaInfo{
|
|
HeaderJars: android.PathsIfNonNil(j.headerJarFile),
|
|
TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
|
|
TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
|
|
AidlIncludeDirs: j.exportAidlIncludeDirs,
|
|
ExportedPlugins: j.exportedPluginJars,
|
|
ExportedPluginClasses: j.exportedPluginClasses,
|
|
ExportedPluginDisableTurbine: j.exportedDisableTurbine,
|
|
})
|
|
|
|
j.outputFile = j.headerJarFile
|
|
return
|
|
}
|
|
|
|
if srcFiles.HasExt(".kt") {
|
|
// When using kotlin sources turbine is used to generate annotation processor sources,
|
|
// including for annotation processors that generate API, so we can use turbine for
|
|
// java sources too.
|
|
disableTurbine = false
|
|
|
|
// user defined kotlin flags.
|
|
kotlincFlags := j.properties.Kotlincflags
|
|
CheckKotlincFlags(ctx, kotlincFlags)
|
|
|
|
// Workaround for KT-46512
|
|
kotlincFlags = append(kotlincFlags, "-Xsam-conversions=class")
|
|
|
|
// 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")
|
|
}
|
|
|
|
for _, plugin := range deps.kotlinPlugins {
|
|
kotlincFlags = append(kotlincFlags, "-Xplugin="+plugin.String())
|
|
}
|
|
flags.kotlincDeps = append(flags.kotlincDeps, deps.kotlinPlugins...)
|
|
|
|
if len(kotlincFlags) > 0 {
|
|
// optimization.
|
|
ctx.Variable(pctx, "kotlincFlags", strings.Join(kotlincFlags, " "))
|
|
flags.kotlincFlags += "$kotlincFlags"
|
|
}
|
|
|
|
// Collect common .kt files for AIDEGen
|
|
j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, kotlinCommonSrcFiles.Strings()...)
|
|
|
|
flags.classpath = append(flags.classpath, deps.kotlinStdlib...)
|
|
flags.classpath = append(flags.classpath, deps.kotlinAnnotations...)
|
|
|
|
flags.kotlincClasspath = append(flags.kotlincClasspath, flags.bootClasspath...)
|
|
flags.kotlincClasspath = append(flags.kotlincClasspath, flags.classpath...)
|
|
|
|
if len(flags.processorPath) > 0 {
|
|
// Use kapt for annotation processing
|
|
kaptSrcJar := android.PathForModuleOut(ctx, "kapt", "kapt-sources.jar")
|
|
kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar")
|
|
kotlinKapt(ctx, kaptSrcJar, kaptResJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
|
|
srcJars = append(srcJars, kaptSrcJar)
|
|
kotlinJars = append(kotlinJars, kaptResJar)
|
|
// Disable annotation processing in javac, it's already been handled by kapt
|
|
flags.processorPath = nil
|
|
flags.processors = nil
|
|
}
|
|
|
|
kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
|
|
kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName)
|
|
kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
|
|
// Make javac rule depend on the kotlinc rule
|
|
flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...)
|
|
|
|
kotlinJars = append(kotlinJars, kotlinJar)
|
|
kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar)
|
|
|
|
// Jar kotlin classes into the final jar after javac
|
|
if BoolDefault(j.properties.Static_kotlin_stdlib, true) {
|
|
kotlinJars = append(kotlinJars, deps.kotlinStdlib...)
|
|
kotlinJars = append(kotlinJars, deps.kotlinAnnotations...)
|
|
kotlinHeaderJars = append(kotlinHeaderJars, deps.kotlinStdlib...)
|
|
kotlinHeaderJars = append(kotlinHeaderJars, deps.kotlinAnnotations...)
|
|
} else {
|
|
flags.dexClasspath = append(flags.dexClasspath, deps.kotlinStdlib...)
|
|
flags.dexClasspath = append(flags.dexClasspath, deps.kotlinAnnotations...)
|
|
}
|
|
}
|
|
|
|
jars := append(android.Paths(nil), kotlinJars...)
|
|
|
|
j.compiledSrcJars = srcJars
|
|
|
|
enableSharding := false
|
|
var headerJarFileWithoutDepsOrJarjar android.Path
|
|
if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine {
|
|
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
|
|
enableSharding = true
|
|
// Formerly, there was a check here that prevented annotation processors
|
|
// from being used when sharding was enabled, as some annotation processors
|
|
// do not function correctly in sharded environments. It was removed to
|
|
// allow for the use of annotation processors that do function correctly
|
|
// with sharding enabled. See: b/77284273.
|
|
}
|
|
extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
|
|
headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
|
|
j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
}
|
|
if len(uniqueJavaFiles) > 0 || len(srcJars) > 0 {
|
|
hasErrorproneableFiles := false
|
|
for _, ext := range j.sourceExtensions {
|
|
if ext != ".proto" && ext != ".aidl" {
|
|
// Skip running errorprone on pure proto or pure aidl modules. Some modules take a long time to
|
|
// compile, and it's not useful to have warnings on these generated sources.
|
|
hasErrorproneableFiles = true
|
|
break
|
|
}
|
|
}
|
|
var extraJarDeps android.Paths
|
|
if Bool(j.properties.Errorprone.Enabled) {
|
|
// If error-prone is enabled, enable errorprone flags on the regular
|
|
// build.
|
|
flags = enableErrorproneFlags(flags)
|
|
} else if hasErrorproneableFiles && ctx.Config().RunErrorProne() && j.properties.Errorprone.Enabled == nil {
|
|
// Otherwise, if the RUN_ERROR_PRONE environment variable is set, create
|
|
// a new jar file just for compiling with the errorprone compiler to.
|
|
// This is because we don't want to cause the java files to get completely
|
|
// rebuilt every time the state of the RUN_ERROR_PRONE variable changes.
|
|
// We also don't want to run this if errorprone is enabled by default for
|
|
// this module, or else we could have duplicated errorprone messages.
|
|
errorproneFlags := enableErrorproneFlags(flags)
|
|
errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
|
|
errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar")
|
|
|
|
transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil,
|
|
"errorprone", "errorprone")
|
|
|
|
extraJarDeps = append(extraJarDeps, errorprone)
|
|
}
|
|
|
|
if enableSharding {
|
|
if headerJarFileWithoutDepsOrJarjar != nil {
|
|
flags.classpath = append(classpath{headerJarFileWithoutDepsOrJarjar}, flags.classpath...)
|
|
}
|
|
shardSize := int(*(j.properties.Javac_shard_size))
|
|
var shardSrcs []android.Paths
|
|
if len(uniqueJavaFiles) > 0 {
|
|
shardSrcs = android.ShardPaths(uniqueJavaFiles, shardSize)
|
|
for idx, shardSrc := range shardSrcs {
|
|
classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc,
|
|
nil, flags, extraJarDeps)
|
|
jars = append(jars, classes)
|
|
}
|
|
}
|
|
// Assume approximately 5 sources per srcjar.
|
|
// For framework-minus-apex in AOSP at the time this was written, there are 266 srcjars, with a mean
|
|
// of 5.8 sources per srcjar, but a median of 1, a standard deviation of 10, and a max of 48 source files.
|
|
if len(srcJars) > 0 {
|
|
startIdx := len(shardSrcs)
|
|
shardSrcJarsList := android.ShardPaths(srcJars, shardSize/5)
|
|
for idx, shardSrcJars := range shardSrcJarsList {
|
|
classes := j.compileJavaClasses(ctx, jarName, startIdx+idx,
|
|
nil, shardSrcJars, flags, extraJarDeps)
|
|
jars = append(jars, classes)
|
|
}
|
|
}
|
|
} else {
|
|
classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
|
|
jars = append(jars, classes)
|
|
}
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
}
|
|
|
|
j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
|
|
|
|
var includeSrcJar android.WritablePath
|
|
if Bool(j.properties.Include_srcs) {
|
|
includeSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+".srcjar")
|
|
TransformResourcesToJar(ctx, includeSrcJar, j.srcJarArgs, j.srcJarDeps)
|
|
}
|
|
|
|
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)
|
|
extraArgs, extraDeps := resourcePathsToJarArgs(j.extraResources), j.extraResources
|
|
|
|
var resArgs []string
|
|
var resDeps android.Paths
|
|
|
|
resArgs = append(resArgs, dirArgs...)
|
|
resDeps = append(resDeps, dirDeps...)
|
|
|
|
resArgs = append(resArgs, fileArgs...)
|
|
resDeps = append(resDeps, fileDeps...)
|
|
|
|
resArgs = append(resArgs, extraArgs...)
|
|
resDeps = append(resDeps, extraDeps...)
|
|
|
|
if len(resArgs) > 0 {
|
|
resourceJar := android.PathForModuleOut(ctx, "res", jarName)
|
|
TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps)
|
|
j.resourceJar = resourceJar
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
}
|
|
|
|
var resourceJars android.Paths
|
|
if j.resourceJar != nil {
|
|
resourceJars = append(resourceJars, j.resourceJar)
|
|
}
|
|
if Bool(j.properties.Include_srcs) {
|
|
resourceJars = append(resourceJars, includeSrcJar)
|
|
}
|
|
resourceJars = append(resourceJars, deps.staticResourceJars...)
|
|
|
|
if len(resourceJars) > 1 {
|
|
combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
|
|
TransformJarsToJar(ctx, combinedJar, "for resources", resourceJars, android.OptionalPath{},
|
|
false, nil, nil)
|
|
j.resourceJar = combinedJar
|
|
} else if len(resourceJars) == 1 {
|
|
j.resourceJar = resourceJars[0]
|
|
}
|
|
|
|
if len(deps.staticJars) > 0 {
|
|
jars = append(jars, deps.staticJars...)
|
|
}
|
|
|
|
manifest := j.overrideManifest
|
|
if !manifest.Valid() && j.properties.Manifest != nil {
|
|
manifest = android.OptionalPathForPath(android.PathForModuleSrc(ctx, *j.properties.Manifest))
|
|
}
|
|
|
|
services := android.PathsForModuleSrc(ctx, j.properties.Services)
|
|
if len(services) > 0 {
|
|
servicesJar := android.PathForModuleOut(ctx, "services", jarName)
|
|
var zipargs []string
|
|
for _, file := range services {
|
|
serviceFile := file.String()
|
|
zipargs = append(zipargs, "-C", filepath.Dir(serviceFile), "-f", serviceFile)
|
|
}
|
|
rule := zip
|
|
args := map[string]string{
|
|
"jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "),
|
|
}
|
|
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ZIP") {
|
|
rule = zipRE
|
|
args["implicits"] = strings.Join(services.Strings(), ",")
|
|
}
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: rule,
|
|
Output: servicesJar,
|
|
Implicits: services,
|
|
Args: args,
|
|
})
|
|
jars = append(jars, servicesJar)
|
|
}
|
|
|
|
jars = append(android.CopyOf(extraCombinedJars), jars...)
|
|
|
|
// 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.OutputPath
|
|
|
|
if len(jars) == 1 && !manifest.Valid() {
|
|
// Optimization: skip the combine step as 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.
|
|
|
|
// moduleStubLinkType determines if the module is the TopLevelStubLibrary generated
|
|
// from sdk_library. The TopLevelStubLibrary contains only one static lib,
|
|
// either with .from-source or .from-text suffix.
|
|
// outputFile should be agnostic to the build configuration,
|
|
// thus "combine" the single static lib in order to prevent the static lib from being exposed
|
|
// to the copy rules.
|
|
stub, _ := moduleStubLinkType(ctx.ModuleName())
|
|
|
|
// Transform the single path to the jar into an OutputPath as that is required by the following
|
|
// code.
|
|
if moduleOutPath, ok := jars[0].(android.ModuleOutPath); ok && !stub {
|
|
// The path contains an embedded OutputPath so reuse that.
|
|
outputFile = moduleOutPath.OutputPath
|
|
} else if outputPath, ok := jars[0].(android.OutputPath); ok && !stub {
|
|
// The path is an OutputPath so reuse it directly.
|
|
outputFile = outputPath
|
|
} else {
|
|
// The file is not in the out directory so create an OutputPath into which it can be copied
|
|
// and which the following code can use to refer to it.
|
|
combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: android.Cp,
|
|
Input: jars[0],
|
|
Output: combinedJar,
|
|
})
|
|
outputFile = combinedJar.OutputPath
|
|
}
|
|
} else {
|
|
combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
|
|
TransformJarsToJar(ctx, combinedJar, "for javac", jars, manifest,
|
|
false, nil, nil)
|
|
outputFile = combinedJar.OutputPath
|
|
}
|
|
|
|
// jarjar implementation jar if necessary
|
|
if j.expandJarjarRules != nil {
|
|
// Transform classes.jar into classes-jarjar.jar
|
|
jarjarFile := android.PathForModuleOut(ctx, "jarjar", jarName).OutputPath
|
|
TransformJarJar(ctx, jarjarFile, outputFile, j.expandJarjarRules)
|
|
outputFile = jarjarFile
|
|
|
|
// jarjar resource jar if necessary
|
|
if j.resourceJar != nil {
|
|
resourceJarJarFile := android.PathForModuleOut(ctx, "res-jarjar", jarName)
|
|
TransformJarJar(ctx, resourceJarJarFile, j.resourceJar, j.expandJarjarRules)
|
|
j.resourceJar = resourceJarJarFile
|
|
}
|
|
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
}
|
|
|
|
// Check package restrictions if necessary.
|
|
if len(j.properties.Permitted_packages) > 0 {
|
|
// Time stamp file created by the package check rule.
|
|
pkgckFile := android.PathForModuleOut(ctx, "package-check.stamp")
|
|
|
|
// Create a rule to copy the output jar to another path and add a validate dependency that
|
|
// will check that the jar only contains the permitted packages. The new location will become
|
|
// the output file of this module.
|
|
inputFile := outputFile
|
|
outputFile = android.PathForModuleOut(ctx, "package-check", jarName).OutputPath
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: android.Cp,
|
|
Input: inputFile,
|
|
Output: outputFile,
|
|
// Make sure that any dependency on the output file will cause ninja to run the package check
|
|
// rule.
|
|
Validation: pkgckFile,
|
|
})
|
|
|
|
// Check packages and create a timestamp file when complete.
|
|
CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages)
|
|
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
}
|
|
|
|
j.implementationJarFile = outputFile
|
|
if j.headerJarFile == nil {
|
|
// If this module couldn't generate a header jar (for example due to api generating annotation processors)
|
|
// then use the implementation jar. Run it through zip2zip first to remove any files in META-INF/services
|
|
// so that javac on modules that depend on this module don't pick up annotation processors (which may be
|
|
// missing their implementations) from META-INF/services/javax.annotation.processing.Processor.
|
|
headerJarFile := android.PathForModuleOut(ctx, "javac-header", jarName)
|
|
convertImplementationJarToHeaderJar(ctx, j.implementationJarFile, headerJarFile)
|
|
j.headerJarFile = headerJarFile
|
|
}
|
|
|
|
// enforce syntax check to jacoco filters for any build (http://b/183622051)
|
|
specs := j.jacocoModuleToZipCommand(ctx)
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
|
|
if j.shouldInstrument(ctx) {
|
|
outputFile = j.instrument(ctx, flags, outputFile, jarName, specs)
|
|
}
|
|
|
|
// merge implementation jar with resources if necessary
|
|
implementationAndResourcesJar := outputFile
|
|
if j.resourceJar != nil {
|
|
jars := android.Paths{j.resourceJar, implementationAndResourcesJar}
|
|
combinedJar := android.PathForModuleOut(ctx, "withres", jarName).OutputPath
|
|
TransformJarsToJar(ctx, combinedJar, "for resources", jars, manifest,
|
|
false, nil, nil)
|
|
implementationAndResourcesJar = combinedJar
|
|
}
|
|
|
|
j.implementationAndResourcesJar = implementationAndResourcesJar
|
|
|
|
// Enable dex compilation for the APEX variants, unless it is disabled explicitly
|
|
compileDex := j.dexProperties.Compile_dex
|
|
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
|
|
if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
|
|
if compileDex == nil {
|
|
compileDex = proptools.BoolPtr(true)
|
|
}
|
|
if j.deviceProperties.Hostdex == nil {
|
|
j.deviceProperties.Hostdex = proptools.BoolPtr(true)
|
|
}
|
|
}
|
|
|
|
if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) {
|
|
if j.hasCode(ctx) {
|
|
if j.shouldInstrumentStatic(ctx) {
|
|
j.dexer.extraProguardFlagsFiles = append(j.dexer.extraProguardFlagsFiles,
|
|
android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags"))
|
|
}
|
|
// Dex compilation
|
|
var dexOutputFile android.OutputPath
|
|
params := &compileDexParams{
|
|
flags: flags,
|
|
sdkVersion: j.SdkVersion(ctx),
|
|
minSdkVersion: j.MinSdkVersion(ctx),
|
|
classesJar: implementationAndResourcesJar,
|
|
jarName: jarName,
|
|
}
|
|
dexOutputFile = j.dexer.compileDex(ctx, params)
|
|
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).OutputPath
|
|
TransformJarsToJar(ctx, combinedJar, "for dex resources", jars, android.OptionalPath{},
|
|
false, nil, nil)
|
|
if *j.dexProperties.Uncompress_dex {
|
|
combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName).OutputPath
|
|
TransformZipAlign(ctx, combinedAlignedJar, combinedJar, nil)
|
|
dexOutputFile = combinedAlignedJar
|
|
} else {
|
|
dexOutputFile = combinedJar
|
|
}
|
|
}
|
|
|
|
// Initialize the hiddenapi structure.
|
|
|
|
j.initHiddenAPI(ctx, makeDexJarPathFromPath(dexOutputFile), j.implementationJarFile, j.dexProperties.Uncompress_dex)
|
|
|
|
// Encode hidden API flags in dex file, if needed.
|
|
dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
|
|
|
|
j.dexJarFile = makeDexJarPathFromPath(dexOutputFile)
|
|
|
|
// Dexpreopting
|
|
j.dexpreopt(ctx, dexOutputFile)
|
|
|
|
outputFile = dexOutputFile
|
|
} else {
|
|
// There is no code to compile into a dex jar, make sure the resources are propagated
|
|
// to the APK if this is an app.
|
|
outputFile = implementationAndResourcesJar
|
|
j.dexJarFile = makeDexJarPathFromPath(j.resourceJar)
|
|
}
|
|
|
|
if ctx.Failed() {
|
|
return
|
|
}
|
|
} else {
|
|
outputFile = implementationAndResourcesJar
|
|
}
|
|
|
|
if ctx.Device() {
|
|
lintSDKVersion := func(apiLevel android.ApiLevel) int {
|
|
if !apiLevel.IsPreview() {
|
|
return apiLevel.FinalInt()
|
|
} else {
|
|
// When running metalava, we pass --version-codename. When that value
|
|
// is not REL, metalava will add 1 to the --current-version argument.
|
|
// On old branches, PLATFORM_SDK_VERSION is the latest version (for that
|
|
// branch) and the codename is REL, except potentially on the most
|
|
// recent non-master branch. On that branch, it goes through two other
|
|
// phases before it gets to the phase previously described:
|
|
// - PLATFORM_SDK_VERSION has not been updated yet, and the codename
|
|
// is not rel. This happens for most of the internal branch's life
|
|
// while the branch has been cut but is still under active development.
|
|
// - PLATFORM_SDK_VERSION has been set, but the codename is still not
|
|
// REL. This happens briefly during the release process. During this
|
|
// state the code to add --current-version is commented out, and then
|
|
// that commenting out is reverted after the codename is set to REL.
|
|
// On the master branch, the PLATFORM_SDK_VERSION always represents a
|
|
// prior version and the codename is always non-REL.
|
|
//
|
|
// We need to add one here to match metalava adding 1. Technically
|
|
// this means that in the state described in the second bullet point
|
|
// above, this number is 1 higher than it should be.
|
|
return ctx.Config().PlatformSdkVersion().FinalInt() + 1
|
|
}
|
|
}
|
|
|
|
j.linter.name = ctx.ModuleName()
|
|
j.linter.srcs = append(srcFiles, nonGeneratedSrcJars...)
|
|
j.linter.srcJars, _ = android.FilterPathList(srcJars, nonGeneratedSrcJars)
|
|
j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...)
|
|
j.linter.classes = j.implementationJarFile
|
|
j.linter.minSdkVersion = lintSDKVersion(j.MinSdkVersion(ctx))
|
|
j.linter.targetSdkVersion = lintSDKVersion(j.TargetSdkVersion(ctx))
|
|
j.linter.compileSdkVersion = lintSDKVersion(j.SdkVersion(ctx).ApiLevel)
|
|
j.linter.compileSdkKind = j.SdkVersion(ctx).Kind
|
|
j.linter.javaLanguageLevel = flags.javaVersion.String()
|
|
j.linter.kotlinLanguageLevel = "1.3"
|
|
if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() {
|
|
j.linter.buildModuleReportZip = true
|
|
}
|
|
j.linter.lint(ctx)
|
|
}
|
|
|
|
j.collectTransitiveSrcFiles(ctx, srcFiles)
|
|
|
|
ctx.CheckbuildFile(outputFile)
|
|
|
|
aconfig.CollectDependencyAconfigFiles(ctx, &j.mergedAconfigFiles)
|
|
|
|
ctx.SetProvider(JavaInfoProvider, JavaInfo{
|
|
HeaderJars: android.PathsIfNonNil(j.headerJarFile),
|
|
TransitiveLibsHeaderJars: j.transitiveLibsHeaderJars,
|
|
TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
|
|
ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar),
|
|
ImplementationJars: android.PathsIfNonNil(j.implementationJarFile),
|
|
ResourceJars: android.PathsIfNonNil(j.resourceJar),
|
|
AidlIncludeDirs: j.exportAidlIncludeDirs,
|
|
SrcJarArgs: j.srcJarArgs,
|
|
SrcJarDeps: j.srcJarDeps,
|
|
TransitiveSrcFiles: j.transitiveSrcFiles,
|
|
ExportedPlugins: j.exportedPluginJars,
|
|
ExportedPluginClasses: j.exportedPluginClasses,
|
|
ExportedPluginDisableTurbine: j.exportedDisableTurbine,
|
|
JacocoReportClassesFile: j.jacocoReportClassesFile,
|
|
})
|
|
|
|
// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
|
|
j.outputFile = outputFile.WithoutRel()
|
|
}
|
|
|
|
func (j *Module) useCompose() bool {
|
|
return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
|
|
}
|
|
|
|
func (j *Module) collectProguardSpecInfo(ctx android.ModuleContext) ProguardSpecInfo {
|
|
transitiveUnconditionalExportedFlags := []*android.DepSet[android.Path]{}
|
|
transitiveProguardFlags := []*android.DepSet[android.Path]{}
|
|
|
|
ctx.VisitDirectDeps(func(m android.Module) {
|
|
depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
|
|
depTag := ctx.OtherModuleDependencyTag(m)
|
|
|
|
if depProguardInfo.UnconditionallyExportedProguardFlags != nil {
|
|
transitiveUnconditionalExportedFlags = append(transitiveUnconditionalExportedFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
|
|
transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
|
|
}
|
|
|
|
if depTag == staticLibTag && depProguardInfo.ProguardFlagsFiles != nil {
|
|
transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.ProguardFlagsFiles)
|
|
}
|
|
})
|
|
|
|
directUnconditionalExportedFlags := android.Paths{}
|
|
proguardFlagsForThisModule := android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)
|
|
exportUnconditionally := proptools.Bool(j.dexProperties.Optimize.Export_proguard_flags_files)
|
|
if exportUnconditionally {
|
|
// if we explicitly export, then our unconditional exports are the same as our transitive flags
|
|
transitiveUnconditionalExportedFlags = transitiveProguardFlags
|
|
directUnconditionalExportedFlags = proguardFlagsForThisModule
|
|
}
|
|
|
|
return ProguardSpecInfo{
|
|
Export_proguard_flags_files: exportUnconditionally,
|
|
ProguardFlagsFiles: android.NewDepSet[android.Path](
|
|
android.POSTORDER,
|
|
proguardFlagsForThisModule,
|
|
transitiveProguardFlags,
|
|
),
|
|
UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path](
|
|
android.POSTORDER,
|
|
directUnconditionalExportedFlags,
|
|
transitiveUnconditionalExportedFlags,
|
|
),
|
|
}
|
|
|
|
}
|
|
|
|
// Returns a copy of the supplied flags, but with all the errorprone-related
|
|
// fields copied to the regular build's fields.
|
|
func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {
|
|
flags.processorPath = append(flags.errorProneProcessorPath, flags.processorPath...)
|
|
|
|
if len(flags.errorProneExtraJavacFlags) > 0 {
|
|
if len(flags.javacFlags) > 0 {
|
|
flags.javacFlags += " " + flags.errorProneExtraJavacFlags
|
|
} else {
|
|
flags.javacFlags = flags.errorProneExtraJavacFlags
|
|
}
|
|
}
|
|
return flags
|
|
}
|
|
|
|
func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, idx int,
|
|
srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.WritablePath {
|
|
|
|
kzipName := pathtools.ReplaceExtension(jarName, "kzip")
|
|
annoSrcJar := android.PathForModuleOut(ctx, "javac", "anno.srcjar")
|
|
if idx >= 0 {
|
|
kzipName = strings.TrimSuffix(jarName, filepath.Ext(jarName)) + strconv.Itoa(idx) + ".kzip"
|
|
annoSrcJar = android.PathForModuleOut(ctx, "javac", "anno-"+strconv.Itoa(idx)+".srcjar")
|
|
jarName += strconv.Itoa(idx)
|
|
}
|
|
|
|
classes := android.PathForModuleOut(ctx, "javac", jarName).OutputPath
|
|
TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps)
|
|
|
|
if ctx.Config().EmitXrefRules() {
|
|
extractionFile := android.PathForModuleOut(ctx, kzipName)
|
|
emitXrefRule(ctx, extractionFile, idx, srcFiles, srcJars, flags, extraJarDeps)
|
|
j.kytheFiles = append(j.kytheFiles, extractionFile)
|
|
}
|
|
|
|
if len(flags.processorPath) > 0 {
|
|
j.annoSrcJars = append(j.annoSrcJars, annoSrcJar)
|
|
}
|
|
|
|
return classes
|
|
}
|
|
|
|
// 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) (headerJar, jarjarAndDepsHeaderJar 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, nil
|
|
}
|
|
jars = append(jars, turbineJar)
|
|
headerJar = 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.
|
|
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/TRANSITIVE"})
|
|
jarjarAndDepsHeaderJar = combinedJar
|
|
|
|
if j.expandJarjarRules != nil {
|
|
// Transform classes.jar into classes-jarjar.jar
|
|
jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
|
|
TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules)
|
|
jarjarAndDepsHeaderJar = jarjarFile
|
|
if ctx.Failed() {
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
return headerJar, jarjarAndDepsHeaderJar
|
|
}
|
|
|
|
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
|
|
classesJar android.Path, jarName string, specs string) android.OutputPath {
|
|
|
|
jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco-report-classes", jarName)
|
|
instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName).OutputPath
|
|
|
|
jacocoInstrumentJar(ctx, instrumentedJar, jacocoReportClassesFile, classesJar, specs)
|
|
|
|
j.jacocoReportClassesFile = jacocoReportClassesFile
|
|
|
|
return instrumentedJar
|
|
}
|
|
|
|
type providesTransitiveHeaderJars struct {
|
|
// set of header jars for all transitive libs deps
|
|
transitiveLibsHeaderJars *android.DepSet[android.Path]
|
|
// set of header jars for all transitive static libs deps
|
|
transitiveStaticLibsHeaderJars *android.DepSet[android.Path]
|
|
}
|
|
|
|
func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet[android.Path] {
|
|
return j.transitiveLibsHeaderJars
|
|
}
|
|
|
|
func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet[android.Path] {
|
|
return j.transitiveStaticLibsHeaderJars
|
|
}
|
|
|
|
func (j *providesTransitiveHeaderJars) collectTransitiveHeaderJars(ctx android.ModuleContext) {
|
|
directLibs := android.Paths{}
|
|
directStaticLibs := android.Paths{}
|
|
transitiveLibs := []*android.DepSet[android.Path]{}
|
|
transitiveStaticLibs := []*android.DepSet[android.Path]{}
|
|
ctx.VisitDirectDeps(func(module android.Module) {
|
|
// don't add deps of the prebuilt version of the same library
|
|
if ctx.ModuleName() == android.RemoveOptionalPrebuiltPrefix(module.Name()) {
|
|
return
|
|
}
|
|
|
|
dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
|
|
tag := ctx.OtherModuleDependencyTag(module)
|
|
_, isUsesLibDep := tag.(usesLibraryDependencyTag)
|
|
if tag == libTag || tag == r8LibraryJarTag || isUsesLibDep {
|
|
directLibs = append(directLibs, dep.HeaderJars...)
|
|
} else if tag == staticLibTag {
|
|
directStaticLibs = append(directStaticLibs, dep.HeaderJars...)
|
|
} else {
|
|
// Don't propagate transitive libs for other kinds of dependencies.
|
|
return
|
|
}
|
|
|
|
if dep.TransitiveLibsHeaderJars != nil {
|
|
transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
|
|
}
|
|
if dep.TransitiveStaticLibsHeaderJars != nil {
|
|
transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
|
|
}
|
|
})
|
|
j.transitiveLibsHeaderJars = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
|
|
j.transitiveStaticLibsHeaderJars = android.NewDepSet(android.POSTORDER, directStaticLibs, transitiveStaticLibs)
|
|
}
|
|
|
|
func (j *Module) HeaderJars() android.Paths {
|
|
if j.headerJarFile == nil {
|
|
return nil
|
|
}
|
|
return android.Paths{j.headerJarFile}
|
|
}
|
|
|
|
func (j *Module) ImplementationJars() android.Paths {
|
|
if j.implementationJarFile == nil {
|
|
return nil
|
|
}
|
|
return android.Paths{j.implementationJarFile}
|
|
}
|
|
|
|
func (j *Module) DexJarBuildPath() OptionalDexJarPath {
|
|
return j.dexJarFile
|
|
}
|
|
|
|
func (j *Module) DexJarInstallPath() android.Path {
|
|
return j.installFile
|
|
}
|
|
|
|
func (j *Module) ImplementationAndResourcesJars() android.Paths {
|
|
if j.implementationAndResourcesJar == nil {
|
|
return nil
|
|
}
|
|
return android.Paths{j.implementationAndResourcesJar}
|
|
}
|
|
|
|
func (j *Module) AidlIncludeDirs() android.Paths {
|
|
// exportAidlIncludeDirs is type android.Paths already
|
|
return j.exportAidlIncludeDirs
|
|
}
|
|
|
|
func (j *Module) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
|
|
return j.classLoaderContexts
|
|
}
|
|
|
|
// 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.SrcJars = append(dpInfo.SrcJars, j.compiledSrcJars.Strings()...)
|
|
dpInfo.Aidl_include_dirs = append(dpInfo.Aidl_include_dirs, j.deviceProperties.Aidl.Include_dirs...)
|
|
if j.expandJarjarRules != nil {
|
|
dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
|
|
}
|
|
dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...)
|
|
dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...)
|
|
dpInfo.SrcJars = append(dpInfo.SrcJars, j.annoSrcJars.Strings()...)
|
|
}
|
|
|
|
func (j *Module) CompilerDeps() []string {
|
|
jdeps := []string{}
|
|
jdeps = append(jdeps, j.properties.Libs...)
|
|
jdeps = append(jdeps, j.properties.Static_libs...)
|
|
return jdeps
|
|
}
|
|
|
|
func (j *Module) hasCode(ctx android.ModuleContext) bool {
|
|
srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
|
|
return len(srcFiles) > 0 || len(ctx.GetDirectDepsWithTag(staticLibTag)) > 0
|
|
}
|
|
|
|
// Implements android.ApexModule
|
|
func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
|
|
return j.depIsInSameApex(ctx, dep)
|
|
}
|
|
|
|
// Implements android.ApexModule
|
|
func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
|
|
sdkVersionSpec := j.SdkVersion(ctx)
|
|
minSdkVersion := j.MinSdkVersion(ctx)
|
|
if !minSdkVersion.Specified() {
|
|
return fmt.Errorf("min_sdk_version is not specified")
|
|
}
|
|
// If the module is compiling against core (via sdk_version), skip comparison check.
|
|
if sdkVersionSpec.Kind == android.SdkCore {
|
|
return nil
|
|
}
|
|
if minSdkVersion.GreaterThan(sdkVersion) {
|
|
return fmt.Errorf("newer SDK(%v)", minSdkVersion)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (j *Module) Stem() string {
|
|
if j.stem == "" {
|
|
panic("Stem() called before stem property was set")
|
|
}
|
|
return j.stem
|
|
}
|
|
|
|
func (j *Module) JacocoReportClassesFile() android.Path {
|
|
return j.jacocoReportClassesFile
|
|
}
|
|
|
|
func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) {
|
|
var fromDeps []*android.DepSet[android.Path]
|
|
ctx.VisitDirectDeps(func(module android.Module) {
|
|
tag := ctx.OtherModuleDependencyTag(module)
|
|
if tag == staticLibTag {
|
|
depInfo := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
|
|
if depInfo.TransitiveSrcFiles != nil {
|
|
fromDeps = append(fromDeps, depInfo.TransitiveSrcFiles)
|
|
}
|
|
}
|
|
})
|
|
|
|
j.transitiveSrcFiles = android.NewDepSet(android.POSTORDER, mine, fromDeps)
|
|
}
|
|
|
|
func (j *Module) IsInstallable() bool {
|
|
return Bool(j.properties.Installable)
|
|
}
|
|
|
|
type sdkLinkType int
|
|
|
|
const (
|
|
// TODO(jiyong) rename these for better readability. Make the allowed
|
|
// and disallowed link types explicit
|
|
// order is important here. See rank()
|
|
javaCore sdkLinkType = iota
|
|
javaSdk
|
|
javaSystem
|
|
javaModule
|
|
javaSystemServer
|
|
javaPlatform
|
|
)
|
|
|
|
func (lt sdkLinkType) String() string {
|
|
switch lt {
|
|
case javaCore:
|
|
return "core Java API"
|
|
case javaSdk:
|
|
return "Android API"
|
|
case javaSystem:
|
|
return "system API"
|
|
case javaModule:
|
|
return "module API"
|
|
case javaSystemServer:
|
|
return "system server API"
|
|
case javaPlatform:
|
|
return "private API"
|
|
default:
|
|
panic(fmt.Errorf("unrecognized linktype: %d", lt))
|
|
}
|
|
}
|
|
|
|
// rank determines the total order among sdkLinkType. An SDK link type of rank A can link to
|
|
// another SDK link type of rank B only when B <= A. For example, a module linking to Android SDK
|
|
// can't statically depend on modules that use Platform API.
|
|
func (lt sdkLinkType) rank() int {
|
|
return int(lt)
|
|
}
|
|
|
|
type moduleWithSdkDep interface {
|
|
android.Module
|
|
getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool)
|
|
}
|
|
|
|
func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
|
|
switch name {
|
|
case android.SdkCore.DefaultJavaLibraryName(),
|
|
"legacy.core.platform.api.stubs",
|
|
"stable.core.platform.api.stubs",
|
|
"stub-annotations", "private-stub-annotations-jar",
|
|
"core-lambda-stubs",
|
|
"core-generated-annotation-stubs":
|
|
return javaCore, true
|
|
case android.SdkPublic.DefaultJavaLibraryName():
|
|
return javaSdk, true
|
|
case android.SdkSystem.DefaultJavaLibraryName():
|
|
return javaSystem, true
|
|
case android.SdkModule.DefaultJavaLibraryName():
|
|
return javaModule, true
|
|
case android.SdkSystemServer.DefaultJavaLibraryName():
|
|
return javaSystemServer, true
|
|
case android.SdkTest.DefaultJavaLibraryName():
|
|
return javaSystem, true
|
|
}
|
|
|
|
if stub, linkType := moduleStubLinkType(name); stub {
|
|
return linkType, true
|
|
}
|
|
|
|
ver := m.SdkVersion(ctx)
|
|
switch ver.Kind {
|
|
case android.SdkCore:
|
|
return javaCore, false
|
|
case android.SdkSystem:
|
|
return javaSystem, false
|
|
case android.SdkPublic:
|
|
return javaSdk, false
|
|
case android.SdkModule:
|
|
return javaModule, false
|
|
case android.SdkSystemServer:
|
|
return javaSystemServer, false
|
|
case android.SdkPrivate, android.SdkNone, android.SdkCorePlatform, android.SdkTest:
|
|
return javaPlatform, false
|
|
}
|
|
|
|
if !ver.Valid() {
|
|
panic(fmt.Errorf("sdk_version is invalid. got %q", ver.Raw))
|
|
}
|
|
return javaSdk, false
|
|
}
|
|
|
|
// checkSdkLinkType make sures the given dependency doesn't have a lower SDK link type rank than
|
|
// this module's. See the comment on rank() for details and an example.
|
|
func (j *Module) checkSdkLinkType(
|
|
ctx android.ModuleContext, dep moduleWithSdkDep, tag dependencyTag) {
|
|
if ctx.Host() {
|
|
return
|
|
}
|
|
|
|
myLinkType, stubs := j.getSdkLinkType(ctx, ctx.ModuleName())
|
|
if stubs {
|
|
return
|
|
}
|
|
depLinkType, _ := dep.getSdkLinkType(ctx, ctx.OtherModuleName(dep))
|
|
|
|
if myLinkType.rank() < depLinkType.rank() {
|
|
ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+
|
|
"In order to fix this, consider adjusting sdk_version: OR platform_apis: "+
|
|
"property of the source or target module so that target module is built "+
|
|
"with the same or smaller API set when compared to the source.",
|
|
myLinkType, ctx.OtherModuleName(dep), depLinkType)
|
|
}
|
|
}
|
|
|
|
func (j *Module) collectDeps(ctx android.ModuleContext) deps {
|
|
var deps deps
|
|
|
|
if ctx.Device() {
|
|
sdkDep := decodeSdkDep(ctx, android.SdkContext(j))
|
|
if sdkDep.invalidVersion {
|
|
ctx.AddMissingDependencies(sdkDep.bootclasspath)
|
|
ctx.AddMissingDependencies(sdkDep.java9Classpath)
|
|
} else if sdkDep.useFiles {
|
|
// sdkDep.jar is actually equivalent to turbine header.jar.
|
|
deps.classpath = append(deps.classpath, sdkDep.jars...)
|
|
deps.dexClasspath = append(deps.dexClasspath, sdkDep.jars...)
|
|
deps.aidlPreprocess = sdkDep.aidl
|
|
} else {
|
|
deps.aidlPreprocess = sdkDep.aidl
|
|
}
|
|
}
|
|
|
|
sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName())
|
|
|
|
j.collectTransitiveHeaderJars(ctx)
|
|
ctx.VisitDirectDeps(func(module android.Module) {
|
|
otherName := ctx.OtherModuleName(module)
|
|
tag := ctx.OtherModuleDependencyTag(module)
|
|
|
|
if IsJniDepTag(tag) {
|
|
// Handled by AndroidApp.collectAppDeps
|
|
return
|
|
}
|
|
if tag == certificateTag {
|
|
// Handled by AndroidApp.collectAppDeps
|
|
return
|
|
}
|
|
|
|
if dep, ok := module.(SdkLibraryDependency); ok {
|
|
switch tag {
|
|
case sdkLibTag, libTag:
|
|
depHeaderJars := dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))
|
|
deps.classpath = append(deps.classpath, depHeaderJars...)
|
|
deps.dexClasspath = append(deps.dexClasspath, depHeaderJars...)
|
|
case staticLibTag:
|
|
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
|
|
}
|
|
} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
|
|
dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
|
|
if sdkLinkType != javaPlatform &&
|
|
ctx.OtherModuleHasProvider(module, SyspropPublicStubInfoProvider) {
|
|
// dep is a sysprop implementation library, but this module is not linking against
|
|
// the platform, so it gets the sysprop public stubs library instead. Replace
|
|
// dep with the JavaInfo from the SyspropPublicStubInfoProvider.
|
|
syspropDep := ctx.OtherModuleProvider(module, SyspropPublicStubInfoProvider).(SyspropPublicStubInfo)
|
|
dep = syspropDep.JavaInfo
|
|
}
|
|
switch tag {
|
|
case bootClasspathTag:
|
|
deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...)
|
|
case sdkLibTag, libTag, instrumentationForTag:
|
|
if _, ok := module.(*Plugin); ok {
|
|
ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName)
|
|
}
|
|
deps.classpath = append(deps.classpath, dep.HeaderJars...)
|
|
deps.dexClasspath = append(deps.dexClasspath, dep.HeaderJars...)
|
|
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
|
|
addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
|
|
deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
|
|
case java9LibTag:
|
|
deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
|
|
case staticLibTag:
|
|
if _, ok := module.(*Plugin); ok {
|
|
ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a static_libs dependency", otherName)
|
|
}
|
|
deps.classpath = append(deps.classpath, dep.HeaderJars...)
|
|
deps.staticJars = append(deps.staticJars, dep.ImplementationJars...)
|
|
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars...)
|
|
deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars...)
|
|
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
|
|
addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
|
|
// Turbine doesn't run annotation processors, so any module that uses an
|
|
// annotation processor that generates API is incompatible with the turbine
|
|
// optimization.
|
|
deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
|
|
case pluginTag:
|
|
if plugin, ok := module.(*Plugin); ok {
|
|
if plugin.pluginProperties.Processor_class != nil {
|
|
addPlugins(&deps, dep.ImplementationAndResourcesJars, *plugin.pluginProperties.Processor_class)
|
|
} else {
|
|
addPlugins(&deps, dep.ImplementationAndResourcesJars)
|
|
}
|
|
// Turbine doesn't run annotation processors, so any module that uses an
|
|
// annotation processor that generates API is incompatible with the turbine
|
|
// optimization.
|
|
deps.disableTurbine = deps.disableTurbine || Bool(plugin.pluginProperties.Generates_api)
|
|
} else {
|
|
ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
|
|
}
|
|
case errorpronePluginTag:
|
|
if _, ok := module.(*Plugin); ok {
|
|
deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, dep.ImplementationAndResourcesJars...)
|
|
} else {
|
|
ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
|
|
}
|
|
case exportedPluginTag:
|
|
if plugin, ok := module.(*Plugin); ok {
|
|
j.exportedPluginJars = append(j.exportedPluginJars, dep.ImplementationAndResourcesJars...)
|
|
if plugin.pluginProperties.Processor_class != nil {
|
|
j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.pluginProperties.Processor_class)
|
|
}
|
|
// Turbine doesn't run annotation processors, so any module that uses an
|
|
// annotation processor that generates API is incompatible with the turbine
|
|
// optimization.
|
|
j.exportedDisableTurbine = Bool(plugin.pluginProperties.Generates_api)
|
|
} else {
|
|
ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName)
|
|
}
|
|
case kotlinStdlibTag:
|
|
deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars...)
|
|
case kotlinAnnotationsTag:
|
|
deps.kotlinAnnotations = dep.HeaderJars
|
|
case kotlinPluginTag:
|
|
deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...)
|
|
case syspropPublicStubDepTag:
|
|
// This is a sysprop implementation library, forward the JavaInfoProvider from
|
|
// the corresponding sysprop public stub library as SyspropPublicStubInfoProvider.
|
|
ctx.SetProvider(SyspropPublicStubInfoProvider, SyspropPublicStubInfo{
|
|
JavaInfo: dep,
|
|
})
|
|
}
|
|
} else if dep, ok := module.(android.SourceFileProducer); ok {
|
|
switch tag {
|
|
case sdkLibTag, libTag:
|
|
checkProducesJars(ctx, dep)
|
|
deps.classpath = append(deps.classpath, dep.Srcs()...)
|
|
deps.dexClasspath = 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()...)
|
|
}
|
|
} else {
|
|
switch tag {
|
|
case bootClasspathTag:
|
|
// If a system modules dependency has been added to the bootclasspath
|
|
// then add its libs to the bootclasspath.
|
|
sm := module.(SystemModulesProvider)
|
|
deps.bootClasspath = append(deps.bootClasspath, sm.HeaderJars()...)
|
|
|
|
case systemModulesTag:
|
|
if deps.systemModules != nil {
|
|
panic("Found two system module dependencies")
|
|
}
|
|
sm := module.(SystemModulesProvider)
|
|
outputDir, outputDeps := sm.OutputDirAndDeps()
|
|
deps.systemModules = &systemModules{outputDir, outputDeps}
|
|
|
|
case instrumentationForTag:
|
|
ctx.PropertyErrorf("instrumentation_for", "dependency %q of type %q does not provide JavaInfo so is unsuitable for use with this property", ctx.OtherModuleName(module), ctx.OtherModuleType(module))
|
|
}
|
|
}
|
|
|
|
addCLCFromDep(ctx, module, j.classLoaderContexts)
|
|
})
|
|
|
|
return deps
|
|
}
|
|
|
|
func addPlugins(deps *deps, pluginJars android.Paths, pluginClasses ...string) {
|
|
deps.processorPath = append(deps.processorPath, pluginJars...)
|
|
deps.processorClasses = append(deps.processorClasses, pluginClasses...)
|
|
}
|
|
|
|
// TODO(b/132357300) Generalize SdkLibrarComponentDependency to non-SDK libraries and merge with
|
|
// this interface.
|
|
type ProvidesUsesLib interface {
|
|
ProvidesUsesLib() *string
|
|
}
|
|
|
|
func (j *Module) ProvidesUsesLib() *string {
|
|
return j.usesLibraryProperties.Provides_uses_lib
|
|
}
|
|
|
|
type ModuleWithStem interface {
|
|
Stem() string
|
|
}
|
|
|
|
var _ ModuleWithStem = (*Module)(nil)
|
|
|
|
func (j *Module) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
|
|
switch ctx.ModuleType() {
|
|
case "java_library", "java_library_host", "java_library_static", "tradefed_java_library_host":
|
|
if lib, ok := ctx.Module().(*Library); ok {
|
|
javaLibraryBp2Build(ctx, lib)
|
|
}
|
|
case "java_binary_host":
|
|
if binary, ok := ctx.Module().(*Binary); ok {
|
|
javaBinaryHostBp2Build(ctx, binary)
|
|
}
|
|
case "java_test_host":
|
|
if testHost, ok := ctx.Module().(*TestHost); ok {
|
|
javaTestHostBp2Build(ctx, testHost)
|
|
}
|
|
default:
|
|
ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
|
|
}
|
|
}
|