diff options
75 files changed, 2009 insertions, 720 deletions
diff --git a/android/Android.bp b/android/Android.bp index a32e8f253..f5e5606ef 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -78,9 +78,6 @@ bootstrap_go_package { "variable.go", "visibility.go", "writedocs.go", - - // Lock down environment access last - "env.go", ], testSrcs: [ "android_test.go", diff --git a/android/arch.go b/android/arch.go index 6826f3b0b..e40b6f528 100644 --- a/android/arch.go +++ b/android/arch.go @@ -618,7 +618,7 @@ func archMutator(bpctx blueprint.BottomUpMutatorContext) { } // only the primary arch in the ramdisk / vendor_ramdisk / recovery partition - if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk()) { + if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk() || module.InstallInDebugRamdisk()) { osTargets = []Target{osTargets[0]} } diff --git a/android/bazel.go b/android/bazel.go index b3f9d8863..9468891af 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -129,6 +129,7 @@ var ( // Configure modules in these directories to enable bp2build_available: true or false by default. bp2buildDefaultConfig = Bp2BuildConfig{ "bionic": Bp2BuildDefaultTrueRecursively, + "external/gwp_asan": Bp2BuildDefaultTrueRecursively, "system/core/libcutils": Bp2BuildDefaultTrueRecursively, "system/logging/liblog": Bp2BuildDefaultTrueRecursively, } @@ -138,32 +139,25 @@ var ( "libBionicBenchmarksUtils", // ruperts@, cc_library_static, 'map' file not found "libbionic_spawn_benchmark", // ruperts@, cc_library_static, depends on //system/libbase "libc_jemalloc_wrapper", // ruperts@, cc_library_static, depends on //external/jemalloc_new - "libc_bootstrap", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_init_static", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_init_dynamic", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_tzcode", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_freebsd", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_freebsd_large_stack", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_netbsd", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_openbsd_ndk", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_openbsd_large_stack", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_openbsd", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_gdtoa", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_fortify", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_bionic", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage + "libc_bootstrap", // ruperts@, cc_library_static, 'private/bionic_auxv.h' file not found + "libc_init_static", // ruperts@, cc_library_static, 'private/bionic_elf_tls.h' file not found + "libc_init_dynamic", // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found + "libc_tzcode", // ruperts@, cc_library_static, error: expected expression + "libc_netbsd", // ruperts@, cc_library_static, 'engine.c' file not found + "libc_openbsd_large_stack", // ruperts@, cc_library_static, 'android/log.h' file not found + "libc_openbsd", // ruperts@, cc_library_static, 'android/log.h' file not found + "libc_fortify", // ruperts@, cc_library_static, 'private/bionic_fortify.h' file not found + "libc_bionic", // ruperts@, cc_library_static, 'private/bionic_asm.h' file not found "libc_bionic_ndk", // ruperts@, cc_library_static, depends on //bionic/libc/system_properties - "libc_bionic_systrace", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_pthread", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage + "libc_bionic_systrace", // ruperts@, cc_library_static, 'private/bionic_systrace.h' file not found + "libc_pthread", // ruperts@, cc_library_static, 'private/bionic_defs.h' file not found "libc_syscalls", // ruperts@, cc_library_static, mutator panic cannot get direct dep syscalls-arm64.S of libc_syscalls - "libc_aeabi", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage "libc_ndk", // ruperts@, cc_library_static, depends on //bionic/libm:libm "libc_nopthread", // ruperts@, cc_library_static, depends on //external/arm-optimized-routines "libc_common", // ruperts@, cc_library_static, depends on //bionic/libc:libc_nopthread - "libc_static_dispatch", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - "libc_dynamic_dispatch", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage "libc_common_static", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common "libc_common_shared", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common - "libc_unwind_static", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage + "libc_unwind_static", // ruperts@, cc_library_static, 'private/bionic_elf_tls.h' file not found "libc_nomalloc", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common "libasync_safe", // ruperts@, cc_library_static, 'private/CachedProperty.h' file not found "libc_malloc_debug_backtrace", // ruperts@, cc_library_static, depends on //system/libbase @@ -173,10 +167,7 @@ var ( "liblinker_malloc", // ruperts@, cc_library_static, depends on //system/logging/liblog:liblog "liblinker_debuggerd_stub", // ruperts@, cc_library_static, depends on //system/libbase "libbionic_tests_headers_posix", // ruperts@, cc_library_static, 'complex.h' file not found - "libc_dns", // ruperts@, cc_library_static, 'bionic/libc/async_safe' is a subpackage - - "note_memtag_heap_async", // jingwen@, b/185079815, features.h includes not found - "note_memtag_heap_sync", // jingwen@, b/185079815, features.h includes not found + "libc_dns", // ruperts@, cc_library_static, 'android/log.h' file not found // List of all full_cc_libraries in //bionic, with their immediate failures "libc", // jingwen@, cc_library, depends on //external/gwp_asan @@ -186,6 +177,11 @@ var ( "libm", // jingwen@, cc_library, fatal error: 'freebsd-compat.h' file not found "libseccomp_policy", // jingwen@, cc_library, fatal error: 'seccomp_policy.h' file not found "libstdc++", // jingwen@, cc_library, depends on //external/gwp_asan + + // For mixed builds specifically + "note_memtag_heap_async", // jingwen@, cc_library_static, OK for bp2build but features.h includes not found for mixed builds (b/185079815) + "note_memtag_heap_sync", // jingwen@, cc_library_static, OK for bp2build but features.h includes not found for mixed builds (b/185079815) + "libc_gdtoa", // ruperts@, cc_library_static, OK for bp2build but undefined symbol: __strtorQ for mixed builds } // Used for quicker lookups diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 2697007a5..8d561d277 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -737,7 +737,7 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { // Add ninja file dependencies for files which all bazel invocations require. bazelBuildList := absolutePath(filepath.Join( - filepath.Dir(bootstrap.CmdlineModuleListFile()), "bazel.list")) + filepath.Dir(bootstrap.CmdlineArgs.ModuleListFile), "bazel.list")) ctx.AddNinjaFileDeps(bazelBuildList) data, err := ioutil.ReadFile(bazelBuildList) diff --git a/android/config.go b/android/config.go index 80651bbdf..c170f1ed5 100644 --- a/android/config.go +++ b/android/config.go @@ -345,7 +345,7 @@ func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[st // multiple runs in the same program execution is carried over (such as Bazel // context or environment deps). func ConfigForAdditionalRun(c Config) (Config, error) { - newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile) + newConfig, err := NewConfig(c.srcDir, c.buildDir, c.moduleListFile, c.env) if err != nil { return Config{}, err } @@ -356,12 +356,12 @@ func ConfigForAdditionalRun(c Config) (Config, error) { // NewConfig creates a new Config object. The srcDir argument specifies the path // to the root source directory. It also loads the config file, if found. -func NewConfig(srcDir, buildDir string, moduleListFile string) (Config, error) { +func NewConfig(srcDir, buildDir string, moduleListFile string, availableEnv map[string]string) (Config, error) { // Make a config with default options. config := &config{ ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName), - env: originalEnv, + env: availableEnv, srcDir: srcDir, buildDir: buildDir, @@ -1259,7 +1259,7 @@ func (c *config) CFIEnabledForPath(path string) bool { if len(c.productVariables.CFIIncludePaths) == 0 { return false } - return HasAnyPrefix(path, c.productVariables.CFIIncludePaths) + return HasAnyPrefix(path, c.productVariables.CFIIncludePaths) && !c.CFIDisabledForPath(path) } func (c *config) MemtagHeapDisabledForPath(path string) bool { @@ -1273,14 +1273,14 @@ func (c *config) MemtagHeapAsyncEnabledForPath(path string) bool { if len(c.productVariables.MemtagHeapAsyncIncludePaths) == 0 { return false } - return HasAnyPrefix(path, c.productVariables.MemtagHeapAsyncIncludePaths) + return HasAnyPrefix(path, c.productVariables.MemtagHeapAsyncIncludePaths) && !c.MemtagHeapDisabledForPath(path) } func (c *config) MemtagHeapSyncEnabledForPath(path string) bool { if len(c.productVariables.MemtagHeapSyncIncludePaths) == 0 { return false } - return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) + return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path) } func (c *config) VendorConfig(name string) VendorConfig { diff --git a/android/env.go b/android/env.go deleted file mode 100644 index 725a14559..000000000 --- a/android/env.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package android - -import ( - "android/soong/shared" -) - -// This file supports dependencies on environment variables. During build -// manifest generation, any dependency on an environment variable is added to a -// list. At the end of the build, a JSON file called soong.environment.used is -// written containing the current value of all used environment variables. The -// next time the top-level build script is run, soong_ui parses the compare the -// contents of the used environment variables, then, if they changed, deletes -// soong.environment.used to cause a rebuild. -// -// The dependency of build.ninja on soong.environment.used is declared in -// build.ninja.d - -var originalEnv map[string]string - -func InitEnvironment(envFile string) { - var err error - originalEnv, err = shared.EnvFromFile(envFile) - if err != nil { - panic(err) - } -} diff --git a/android/image.go b/android/image.go index 1a1a423e2..bdb9be04d 100644 --- a/android/image.go +++ b/android/image.go @@ -30,6 +30,11 @@ type ImageInterface interface { // vendor ramdisk partition). VendorRamdiskVariantNeeded(ctx BaseModuleContext) bool + // DebugRamdiskVariantNeeded should return true if the module needs a debug ramdisk variant (installed on the + // debug ramdisk partition: $(PRODUCT_OUT)/debug_ramdisk/first_stage_ramdisk if BOARD_USES_RECOVERY_AS_ROOT is + // true, $(PRODUCT_OUT)/debug_ramdisk otherise). + DebugRamdiskVariantNeeded(ctx BaseModuleContext) bool + // RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the // recovery partition). RecoveryVariantNeeded(ctx BaseModuleContext) bool @@ -60,6 +65,9 @@ const ( // VendorRamdiskVariation means a module to be installed to vendor ramdisk image. VendorRamdiskVariation string = "vendor_ramdisk" + + // DebugRamdiskVariation means a module to be installed to debug ramdisk image. + DebugRamdiskVariation string = "debug_ramdisk" ) // imageMutator creates variants for modules that implement the ImageInterface that @@ -83,6 +91,9 @@ func imageMutator(ctx BottomUpMutatorContext) { if m.VendorRamdiskVariantNeeded(ctx) { variations = append(variations, VendorRamdiskVariation) } + if m.DebugRamdiskVariantNeeded(ctx) { + variations = append(variations, DebugRamdiskVariation) + } if m.RecoveryVariantNeeded(ctx) { variations = append(variations, RecoveryVariation) } diff --git a/android/module.go b/android/module.go index 9f923e2d0..942e07193 100644 --- a/android/module.go +++ b/android/module.go @@ -393,6 +393,7 @@ type ModuleContext interface { InstallInSanitizerDir() bool InstallInRamdisk() bool InstallInVendorRamdisk() bool + InstallInDebugRamdisk() bool InstallInRecovery() bool InstallInRoot() bool InstallBypassMake() bool @@ -450,6 +451,7 @@ type Module interface { InstallInSanitizerDir() bool InstallInRamdisk() bool InstallInVendorRamdisk() bool + InstallInDebugRamdisk() bool InstallInRecovery() bool InstallInRoot() bool InstallBypassMake() bool @@ -753,6 +755,9 @@ type commonProperties struct { // Whether this module is installed to vendor ramdisk Vendor_ramdisk *bool + // Whether this module is installed to debug ramdisk + Debug_ramdisk *bool + // Whether this module is built for non-native architectures (also known as native bridge binary) Native_bridge_supported *bool `android:"arch_variant"` @@ -1540,6 +1545,10 @@ func (m *ModuleBase) InstallInVendorRamdisk() bool { return Bool(m.commonProperties.Vendor_ramdisk) } +func (m *ModuleBase) InstallInDebugRamdisk() bool { + return Bool(m.commonProperties.Debug_ramdisk) +} + func (m *ModuleBase) InstallInRecovery() bool { return Bool(m.commonProperties.Recovery) } @@ -1593,6 +1602,10 @@ func (m *ModuleBase) InVendorRamdisk() bool { return m.base().commonProperties.ImageVariation == VendorRamdiskVariation } +func (m *ModuleBase) InDebugRamdisk() bool { + return m.base().commonProperties.ImageVariation == DebugRamdiskVariation +} + func (m *ModuleBase) InRecovery() bool { return m.base().commonProperties.ImageVariation == RecoveryVariation } @@ -2548,6 +2561,10 @@ func (m *moduleContext) InstallInVendorRamdisk() bool { return m.module.InstallInVendorRamdisk() } +func (m *moduleContext) InstallInDebugRamdisk() bool { + return m.module.InstallInDebugRamdisk() +} + func (m *moduleContext) InstallInRecovery() bool { return m.module.InstallInRecovery() } diff --git a/android/paths.go b/android/paths.go index df1222870..c303c38f5 100644 --- a/android/paths.go +++ b/android/paths.go @@ -107,6 +107,7 @@ type ModuleInstallPathContext interface { InstallInSanitizerDir() bool InstallInRamdisk() bool InstallInVendorRamdisk() bool + InstallInDebugRamdisk() bool InstallInRecovery() bool InstallInRoot() bool InstallBypassMake() bool @@ -416,6 +417,93 @@ func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) b return labels } +// Returns true if a prefix + components[:i] + /Android.bp exists +// TODO(b/185358476) Could check for BUILD file instead of checking for Android.bp file, or ensure BUILD is always generated? +func directoryHasBlueprint(fs pathtools.FileSystem, prefix string, components []string, componentIndex int) bool { + blueprintPath := prefix + if blueprintPath != "" { + blueprintPath = blueprintPath + "/" + } + blueprintPath = blueprintPath + strings.Join(components[:componentIndex+1], "/") + blueprintPath = blueprintPath + "/Android.bp" + if exists, _, _ := fs.Exists(blueprintPath); exists { + return true + } else { + return false + } +} + +// Transform a path (if necessary) to acknowledge package boundaries +// +// e.g. something like +// async_safe/include/async_safe/CHECK.h +// might become +// //bionic/libc/async_safe:include/async_safe/CHECK.h +// if the "async_safe" directory is actually a package and not just a directory. +// +// In particular, paths that extend into packages are transformed into absolute labels beginning with //. +func transformSubpackagePath(ctx BazelConversionPathContext, path bazel.Label) bazel.Label { + var newPath bazel.Label + + // Don't transform Bp_text + newPath.Bp_text = path.Bp_text + + if strings.HasPrefix(path.Label, "//") { + // Assume absolute labels are already correct (e.g. //path/to/some/package:foo.h) + newPath.Label = path.Label + return newPath + } + + newLabel := "" + pathComponents := strings.Split(path.Label, "/") + foundBlueprint := false + // Check the deepest subdirectory first and work upwards + for i := len(pathComponents) - 1; i >= 0; i-- { + pathComponent := pathComponents[i] + var sep string + if !foundBlueprint && directoryHasBlueprint(ctx.Config().fs, ctx.ModuleDir(), pathComponents, i) { + sep = ":" + foundBlueprint = true + } else { + sep = "/" + } + if newLabel == "" { + newLabel = pathComponent + } else { + newLabel = pathComponent + sep + newLabel + } + } + if foundBlueprint { + // Ensure paths end up looking like //bionic/... instead of //./bionic/... + moduleDir := ctx.ModuleDir() + if strings.HasPrefix(moduleDir, ".") { + moduleDir = moduleDir[1:] + } + // Make the path into an absolute label (e.g. //bionic/libc/foo:bar.h instead of just foo:bar.h) + if moduleDir == "" { + newLabel = "//" + newLabel + } else { + newLabel = "//" + moduleDir + "/" + newLabel + } + } + newPath.Label = newLabel + + return newPath +} + +// Transform paths to acknowledge package boundaries +// See transformSubpackagePath() for more information +func transformSubpackagePaths(ctx BazelConversionPathContext, paths bazel.LabelList) bazel.LabelList { + var newPaths bazel.LabelList + for _, include := range paths.Includes { + newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(ctx, include)) + } + for _, exclude := range paths.Excludes { + newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(ctx, exclude)) + } + return newPaths +} + // BazelLabelForModuleSrc returns bazel.LabelList with paths rooted from the module's local source // directory. It expands globs, and resolves references to modules using the ":name" syntax to // bazel-compatible labels. Properties passed as the paths or excludes argument must have been @@ -445,6 +533,7 @@ func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, exclu } labels := expandSrcsForBazel(ctx, paths, excluded) labels.Excludes = excludeLabels.Includes + labels = transformSubpackagePaths(ctx, labels) return labels } @@ -1849,6 +1938,16 @@ func modulePartition(ctx ModuleInstallPathContext, os OsType) string { if !ctx.InstallInRoot() { partition += "/system" } + } else if ctx.InstallInDebugRamdisk() { + // The module is only available after switching root into + // /first_stage_ramdisk. To expose the module before switching root + // on a device without a dedicated recovery partition, install the + // recovery variant. + if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() { + partition = "debug_ramdisk/first_stage_ramdisk" + } else { + partition = "debug_ramdisk" + } } else if ctx.InstallInRecovery() { if ctx.InstallInRoot() { partition = "recovery/root" @@ -2019,6 +2118,7 @@ type testModuleInstallPathContext struct { inSanitizerDir bool inRamdisk bool inVendorRamdisk bool + inDebugRamdisk bool inRecovery bool inRoot bool forceOS *OsType @@ -2051,6 +2151,10 @@ func (m testModuleInstallPathContext) InstallInVendorRamdisk() bool { return m.inVendorRamdisk } +func (m testModuleInstallPathContext) InstallInDebugRamdisk() bool { + return m.inDebugRamdisk +} + func (m testModuleInstallPathContext) InstallInRecovery() bool { return m.inRecovery } diff --git a/android/paths_test.go b/android/paths_test.go index 465ea3b55..cb9138b98 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -21,6 +21,8 @@ import ( "strconv" "strings" "testing" + + "github.com/google/blueprint/proptools" ) type strsTestCase struct { @@ -339,6 +341,73 @@ func TestPathForModuleInstall(t *testing.T) { }, { + name: "ramdisk binary", + ctx: &testModuleInstallPathContext{ + baseModuleContext: baseModuleContext{ + os: deviceTarget.Os, + target: deviceTarget, + }, + inRamdisk: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/ramdisk/system/my_test", + partitionDir: "target/product/test_device/ramdisk/system", + }, + { + name: "ramdisk root binary", + ctx: &testModuleInstallPathContext{ + baseModuleContext: baseModuleContext{ + os: deviceTarget.Os, + target: deviceTarget, + }, + inRamdisk: true, + inRoot: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/ramdisk/my_test", + partitionDir: "target/product/test_device/ramdisk", + }, + { + name: "vendor_ramdisk binary", + ctx: &testModuleInstallPathContext{ + baseModuleContext: baseModuleContext{ + os: deviceTarget.Os, + target: deviceTarget, + }, + inVendorRamdisk: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/vendor_ramdisk/system/my_test", + partitionDir: "target/product/test_device/vendor_ramdisk/system", + }, + { + name: "vendor_ramdisk root binary", + ctx: &testModuleInstallPathContext{ + baseModuleContext: baseModuleContext{ + os: deviceTarget.Os, + target: deviceTarget, + }, + inVendorRamdisk: true, + inRoot: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/vendor_ramdisk/my_test", + partitionDir: "target/product/test_device/vendor_ramdisk", + }, + { + name: "debug_ramdisk binary", + ctx: &testModuleInstallPathContext{ + baseModuleContext: baseModuleContext{ + os: deviceTarget.Os, + target: deviceTarget, + }, + inDebugRamdisk: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/debug_ramdisk/my_test", + partitionDir: "target/product/test_device/debug_ramdisk", + }, + { name: "system native test binary", ctx: &testModuleInstallPathContext{ baseModuleContext: baseModuleContext{ @@ -635,6 +704,80 @@ func TestPathForModuleInstall(t *testing.T) { } } +func TestPathForModuleInstallRecoveryAsBoot(t *testing.T) { + testConfig := pathTestConfig("") + testConfig.TestProductVariables.BoardUsesRecoveryAsBoot = proptools.BoolPtr(true) + testConfig.TestProductVariables.BoardMoveRecoveryResourcesToVendorBoot = proptools.BoolPtr(true) + deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}} + + testCases := []struct { + name string + ctx *testModuleInstallPathContext + in []string + out string + partitionDir string + }{ + { + name: "ramdisk binary", + ctx: &testModuleInstallPathContext{ + baseModuleContext: baseModuleContext{ + os: deviceTarget.Os, + target: deviceTarget, + }, + inRamdisk: true, + inRoot: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/recovery/root/first_stage_ramdisk/my_test", + partitionDir: "target/product/test_device/recovery/root/first_stage_ramdisk", + }, + + { + name: "vendor_ramdisk binary", + ctx: &testModuleInstallPathContext{ + baseModuleContext: baseModuleContext{ + os: deviceTarget.Os, + target: deviceTarget, + }, + inVendorRamdisk: true, + inRoot: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk/my_test", + partitionDir: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk", + }, + { + name: "debug_ramdisk binary", + ctx: &testModuleInstallPathContext{ + baseModuleContext: baseModuleContext{ + os: deviceTarget.Os, + target: deviceTarget, + }, + inDebugRamdisk: true, + }, + in: []string{"my_test"}, + out: "target/product/test_device/debug_ramdisk/first_stage_ramdisk/my_test", + partitionDir: "target/product/test_device/debug_ramdisk/first_stage_ramdisk", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tc.ctx.baseModuleContext.config = testConfig + output := PathForModuleInstall(tc.ctx, tc.in...) + if output.basePath.path != tc.out { + t.Errorf("unexpected path:\n got: %q\nwant: %q\n", + output.basePath.path, + tc.out) + } + if output.partitionDir != tc.partitionDir { + t.Errorf("unexpected partitionDir:\n got: %q\nwant: %q\n", + output.partitionDir, tc.partitionDir) + } + }) + } +} + func TestBaseDirForInstallPath(t *testing.T) { testConfig := pathTestConfig("") deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}} diff --git a/android/prebuilt.go b/android/prebuilt.go index 2fc4782be..40bcdfd8c 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -339,6 +339,13 @@ func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module, prebuil return false } + // Skip prebuilt modules under unexported namespaces so that we won't + // end up shadowing non-prebuilt module when prebuilt module under same + // name happens to have a `Prefer` property set to true. + if ctx.Config().KatiEnabled() && !prebuilt.ExportedToMake() { + return false + } + // TODO: use p.Properties.Name and ctx.ModuleDir to override preference if Bool(p.properties.Prefer) { return true diff --git a/android/sdk_version.go b/android/sdk_version.go index 5fdaa91f4..98db82496 100644 --- a/android/sdk_version.go +++ b/android/sdk_version.go @@ -22,15 +22,15 @@ import ( type SdkContext interface { // SdkVersion returns SdkSpec that corresponds to the sdk_version property of the current module - SdkVersion() SdkSpec + SdkVersion(ctx EarlyModuleContext) SdkSpec // SystemModules returns the system_modules property of the current module, or an empty string if it is not set. SystemModules() string // MinSdkVersion returns SdkSpec that corresponds to the min_sdk_version property of the current module, // or from sdk_version if it is not set. - MinSdkVersion() SdkSpec + MinSdkVersion(ctx EarlyModuleContext) SdkSpec // TargetSdkVersion returns the SdkSpec that corresponds to the target_sdk_version property of the current module, // or from sdk_version if it is not set. - TargetSdkVersion() SdkSpec + TargetSdkVersion(ctx EarlyModuleContext) SdkSpec } // SdkKind represents a particular category of an SDK spec like public, system, test, etc. @@ -201,15 +201,23 @@ func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil } -func SdkSpecFrom(str string) SdkSpec { +var ( + SdkSpecNone = SdkSpec{SdkNone, NoneApiLevel, "(no version)"} + // TODO(b/175678607) ApiLevel of SdkSpecPrivate should be FutureApiLevel + SdkSpecPrivate = SdkSpec{SdkPrivate, NoneApiLevel, ""} + // TODO(b/175678607) ApiLevel of SdkSpecCorePlatform should be FutureApiLevel + SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, NoneApiLevel, "core_platform"} +) + +func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec { switch str { // special cases first case "": - return SdkSpec{SdkPrivate, NoneApiLevel, str} + return SdkSpecPrivate case "none": - return SdkSpec{SdkNone, NoneApiLevel, str} + return SdkSpecNone case "core_platform": - return SdkSpec{SdkCorePlatform, NoneApiLevel, str} + return SdkSpecCorePlatform default: // the syntax is [kind_]version sep := strings.LastIndex(str, "_") @@ -242,15 +250,10 @@ func SdkSpecFrom(str string) SdkSpec { return SdkSpec{SdkInvalid, NoneApiLevel, str} } - var apiLevel ApiLevel - if versionString == "current" { - apiLevel = FutureApiLevel - } else if i, err := strconv.Atoi(versionString); err == nil { - apiLevel = uncheckedFinalApiLevel(i) - } else { + apiLevel, err := ApiLevelFromUser(ctx, versionString) + if err != nil { return SdkSpec{SdkInvalid, apiLevel, str} } - return SdkSpec{kind, apiLevel, str} } } diff --git a/apex/apex.go b/apex/apex.go index 880028f87..0eacf6dcb 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -2272,8 +2272,10 @@ func (a *apexBundle) checkJavaStableSdkVersion(ctx android.ModuleContext) { tag := ctx.OtherModuleDependencyTag(module) switch tag { case javaLibTag, androidAppTag: - if m, ok := module.(interface{ CheckStableSdkVersion() error }); ok { - if err := m.CheckStableSdkVersion(); err != nil { + if m, ok := module.(interface { + CheckStableSdkVersion(ctx android.BaseModuleContext) error + }); ok { + if err := m.CheckStableSdkVersion(ctx); err != nil { ctx.ModuleErrorf("cannot depend on \"%v\": %v", ctx.OtherModuleName(module), err) } } diff --git a/apex/apex_test.go b/apex/apex_test.go index 61e886499..977a9544c 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4566,8 +4566,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { checkHiddenAPIIndexInputs := func(t *testing.T, ctx *android.TestContext, expectedInputs string) { t.Helper() - hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index") - indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index") + platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common") + indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index") java.CheckHiddenAPIRuleInputs(t, expectedInputs, indexRule) } @@ -4826,7 +4826,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { name: "myapex", enabled: false, key: "myapex.key", - java_libs: ["libfoo"], + java_libs: ["libfoo", "libbar"], } apex_key { @@ -4884,8 +4884,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. checkHiddenAPIIndexInputs(t, ctx, ` -.intermediates/prebuilt_libbar/android_common_prebuilt_myapex/hiddenapi/index.csv -.intermediates/prebuilt_libfoo/android_common_prebuilt_myapex/hiddenapi/index.csv +.intermediates/prebuilt_libbar/android_common_myapex/hiddenapi/index.csv +.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv `) }) } @@ -6555,6 +6555,11 @@ func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.F PrepareForTestWithApexBuildComponents, preparer, fs.AddToFixture(), + android.FixtureAddTextFile("frameworks/base/boot/Android.bp", ` + platform_bootclasspath { + name: "platform-bootclasspath", + } + `), ). ExtendWithErrorHandler(errorHandler). RunTestWithBp(t, bp) @@ -6657,13 +6662,13 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) { - err := "failed to find a dex jar path for module 'nonexistent'" + err := `"platform-bootclasspath" depends on undefined module "nonexistent"` preparer := java.FixtureConfigureBootJars("platform:nonexistent") testNoUpdatableJarsInBootImage(t, err, preparer) }) t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) { - err := "failed to find a dex jar path for module 'nonexistent'" + err := `"platform-bootclasspath" depends on undefined module "nonexistent"` preparer := java.FixtureConfigureBootJars("platform:nonexistent") testNoUpdatableJarsInBootImage(t, err, preparer) }) diff --git a/apex/builder.go b/apex/builder.go index 2df380b5a..e59dc96e3 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -517,6 +517,9 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String() prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin") + // Figure out if need to compress apex. + compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false) && !a.testApex + if apexType == imageApex { //////////////////////////////////////////////////////////////////////////////////// // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files @@ -631,7 +634,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { ctx.PropertyErrorf("test_only_no_hashtree", "not available") return } - if moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration() { + if (moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration()) && !compressionEnabled { // Apexes which are supposed to be installed in builtin dirs(/system, etc) // don't need hashtree for activation. Therefore, by removing hashtree from // apex bundle (filesystem image in it, to be specific), we can save storage. @@ -780,12 +783,11 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { }) a.outputFile = signedOutputFile - // Process APEX compression if enabled or forced if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && a.testOnlyShouldForceCompression() { ctx.PropertyErrorf("test_only_force_compression", "not available") return } - compressionEnabled := ctx.Config().CompressedApex() && proptools.BoolDefault(a.properties.Compressible, false) + if apexType == imageApex && (compressionEnabled || a.testOnlyShouldForceCompression()) { a.isCompressed = true unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+".capex.unsigned") @@ -946,16 +948,19 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { depInfos[to.Name()] = info } else { toMinSdkVersion := "(no version)" - if m, ok := to.(interface{ MinSdkVersion() string }); ok { - if v := m.MinSdkVersion(); v != "" { - toMinSdkVersion = v + if m, ok := to.(interface { + MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec + }); ok { + if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() { + toMinSdkVersion = v.ApiLevel.String() } - } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok { - if v := m.MinSdkVersionString(); v != "" { + } else if m, ok := to.(interface{ MinSdkVersion() string }); ok { + // TODO(b/175678607) eliminate the use of MinSdkVersion returning + // string + if v := m.MinSdkVersion(); v != "" { toMinSdkVersion = v } } - depInfos[to.Name()] = android.ApexModuleDepInfo{ To: to.Name(), From: []string{from.Name()}, diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 10a70a3b7..a9d24a7c5 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -172,7 +172,7 @@ func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) { // Create an ApexInfo for the prebuilt_apex. apexInfo := android.ApexInfo{ - ApexVariationName: mctx.ModuleName(), + ApexVariationName: android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName()), InApexes: []string{mctx.ModuleName()}, ApexContents: []*android.ApexContents{apexContents}, ForPrebuiltApex: true, diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go index 427aed355..7e72a8b22 100644 --- a/bp2build/cc_library_static_conversion_test.go +++ b/bp2build/cc_library_static_conversion_test.go @@ -279,6 +279,53 @@ cc_library_static { ], )`}, }, + { + description: "cc_library_static subpackage test", + moduleTypeUnderTest: "cc_library_static", + moduleTypeUnderTestFactory: cc.LibraryStaticFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build, + filesystem: map[string]string{ + // subpackage with subdirectory + "subpackage/Android.bp": "", + "subpackage/subpackage_header.h": "", + "subpackage/subdirectory/subdirectory_header.h": "", + // subsubpackage with subdirectory + "subpackage/subsubpackage/Android.bp": "", + "subpackage/subsubpackage/subsubpackage_header.h": "", + "subpackage/subsubpackage/subdirectory/subdirectory_header.h": "", + // subsubsubpackage with subdirectory + "subpackage/subsubpackage/subsubsubpackage/Android.bp": "", + "subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h": "", + "subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "", + }, + bp: soongCcLibraryStaticPreamble + ` +cc_library_static { + name: "foo_static", + srcs: [ + ], + include_dirs: [ + "subpackage", + ], + + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`cc_library_static( + name = "foo_static", + includes = [ + "subpackage", + ".", + ], + linkstatic = True, + srcs = [ + "//subpackage:subpackage_header.h", + "//subpackage:subdirectory/subdirectory_header.h", + "//subpackage/subsubpackage:subsubpackage_header.h", + "//subpackage/subsubpackage:subdirectory/subdirectory_header.h", + "//subpackage/subsubpackage/subsubsubpackage:subsubsubpackage_header.h", + "//subpackage/subsubpackage/subsubsubpackage:subdirectory/subdirectory_header.h", + ], +)`}, + }, } dir := "." @@ -1113,16 +1113,33 @@ func (c *Module) IsNdk(config android.Config) bool { return inList(c.BaseModuleName(), *getNDKKnownLibs(config)) } -// isLLndk returns true for both LLNDK (public) and LLNDK-private libs. func (c *Module) IsLlndk() bool { return c.VendorProperties.IsLLNDK } -// IsLlndkPublic returns true only for LLNDK (public) libs. func (c *Module) IsLlndkPublic() bool { return c.VendorProperties.IsLLNDK && !c.VendorProperties.IsVNDKPrivate } +func (c *Module) IsLlndkHeaders() bool { + if _, ok := c.linker.(*llndkHeadersDecorator); ok { + return true + } + return false +} + +func (c *Module) IsLlndkLibrary() bool { + if _, ok := c.linker.(*llndkStubDecorator); ok { + return true + } + return false +} + +func (m *Module) HasLlndkStubs() bool { + lib := moduleLibraryInterface(m) + return lib != nil && lib.hasLLNDKStubs() +} + // isImplementationForLLNDKPublic returns true for any variant of a cc_library that has LLNDK stubs // and does not set llndk.vendor_available: false. func (c *Module) isImplementationForLLNDKPublic() bool { @@ -1186,6 +1203,10 @@ func (c *Module) IsVndkExt() bool { return false } +func (c *Module) SubName() string { + return c.Properties.SubName +} + func (c *Module) MustUseVendorVariant() bool { return c.isVndkSp() || c.Properties.MustUseVendorVariant } @@ -1246,7 +1267,7 @@ func (c *Module) nativeCoverage() bool { return c.linker != nil && c.linker.nativeCoverage() } -func (c *Module) isSnapshotPrebuilt() bool { +func (c *Module) IsSnapshotPrebuilt() bool { if p, ok := c.linker.(snapshotInterface); ok { return p.isSnapshotPrebuilt() } @@ -2289,12 +2310,7 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin if ccFrom.vndkdep != nil { ccFrom.vndkdep.vndkCheckLinkType(ctx, ccTo, tag) } - } else if linkableMod, ok := to.(LinkableInterface); ok { - // Static libraries from other languages can be linked - if !linkableMod.Static() { - ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type") - } - } else { + } else if _, ok := to.(LinkableInterface); !ok { ctx.ModuleErrorf("Attempting to link VNDK cc.Module with unsupported module type") } return @@ -2807,7 +2823,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { c.sabi.Properties.ReexportedIncludes, depExporterInfo.IncludeDirs.Strings()...) } - makeLibName := c.makeLibName(ctx, ccDep, depName) + libDepTag.makeSuffix + makeLibName := MakeLibName(ctx, c, ccDep, depName) + libDepTag.makeSuffix switch { case libDepTag.header(): c.Properties.AndroidMkHeaderLibs = append( @@ -2846,7 +2862,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { switch depTag { case runtimeDepTag: c.Properties.AndroidMkRuntimeLibs = append( - c.Properties.AndroidMkRuntimeLibs, c.makeLibName(ctx, ccDep, depName)+libDepTag.makeSuffix) + c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, depName)+libDepTag.makeSuffix) // Record baseLibName for snapshots. c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName)) case objDepTag: @@ -2924,7 +2940,8 @@ func baseLibName(depName string) string { return libName } -func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, depName string) string { +func MakeLibName(ctx android.ModuleContext, c LinkableInterface, ccDep LinkableInterface, depName string) string { + vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) libName := baseLibName(depName) @@ -2934,6 +2951,7 @@ func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk if ccDepModule != nil { + // TODO(ivanlozano) Support snapshots for Rust-produced C library variants. // Use base module name for snapshots when exporting to Makefile. if snapshotPrebuilt, ok := ccDepModule.linker.(snapshotInterface); ok { baseName := ccDepModule.BaseModuleName() @@ -2947,10 +2965,10 @@ func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, // The vendor module is a no-vendor-variant VNDK library. Depend on the // core module instead. return libName - } else if ccDep.UseVndk() && nonSystemVariantsExist && ccDepModule != nil { + } else if ccDep.UseVndk() && nonSystemVariantsExist { // The vendor and product modules in Make will have been renamed to not conflict with the // core module, so update the dependency name here accordingly. - return libName + ccDepModule.Properties.SubName + return libName + ccDep.SubName() } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib { return libName + vendorPublicLibrarySuffix } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() { diff --git a/cc/cc_test.go b/cc/cc_test.go index e4dfc97ad..07dcc951f 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -3921,8 +3921,9 @@ var prepareForTestWithMemtagHeap = android.GroupFixturePreparers( }), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.MemtagHeapExcludePaths = []string{"subdir_exclude"} - variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync"} - variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async"} + // "subdir_exclude" is covered by both include and exclude paths. Exclude wins. + variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_exclude"} + variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_exclude"} }), ) diff --git a/cc/genrule.go b/cc/genrule.go index ca4fda7e2..82d7205da 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -75,6 +75,10 @@ func (g *GenruleExtraProperties) VendorRamdiskVariantNeeded(ctx android.BaseModu return Bool(g.Vendor_ramdisk_available) } +func (g *GenruleExtraProperties) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return false +} + func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { // If the build is using a snapshot, the recovery variant under AOSP directories // is not needed. diff --git a/cc/image.go b/cc/image.go index ca00ac976..bf662c64f 100644 --- a/cc/image.go +++ b/cc/image.go @@ -199,39 +199,72 @@ func (c *Module) compareVendorAndProductProps() bool { return true } -func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { - // Validation check - vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() - productSpecific := mctx.ProductSpecific() +// ImageMutatableModule provides a common image mutation interface for LinkableInterface modules. +type ImageMutatableModule interface { + android.Module + LinkableInterface - if Bool(m.VendorProperties.Vendor_available) { - if vendorSpecific { - mctx.PropertyErrorf("vendor_available", - "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`") - } - if Bool(m.VendorProperties.Odm_available) { - mctx.PropertyErrorf("vendor_available", - "doesn't make sense at the same time as `odm_available: true`") - } - } + // AndroidModuleBase returns the android.ModuleBase for this module + AndroidModuleBase() *android.ModuleBase - if Bool(m.VendorProperties.Odm_available) { - if vendorSpecific { - mctx.PropertyErrorf("odm_available", - "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`") - } - } + // VendorAvailable returns true if this module is available on the vendor image. + VendorAvailable() bool - if Bool(m.VendorProperties.Product_available) { - if productSpecific { - mctx.PropertyErrorf("product_available", - "doesn't make sense at the same time as `product_specific: true`") - } - if vendorSpecific { - mctx.PropertyErrorf("product_available", - "cannot provide product variant from a vendor module. Please use `product_specific: true` with `vendor_available: true`") - } - } + // OdmAvailable returns true if this module is available on the odm image. + OdmAvailable() bool + + // ProductAvailable returns true if this module is available on the product image. + ProductAvailable() bool + + // RamdiskAvailable returns true if this module is available on the ramdisk image. + RamdiskAvailable() bool + + // RecoveryAvailable returns true if this module is available on the recovery image. + RecoveryAvailable() bool + + // VendorRamdiskAvailable returns true if this module is available on the vendor ramdisk image. + VendorRamdiskAvailable() bool + + // IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt. + IsSnapshotPrebuilt() bool + + // SnapshotVersion returns the snapshot version for this module. + SnapshotVersion(mctx android.BaseModuleContext) string + + // SdkVersion returns the SDK version for this module. + SdkVersion() string + + // ExtraVariants returns the list of extra variants this module requires. + ExtraVariants() []string + + // AppendExtraVariant returns an extra variant to the list of extra variants this module requires. + AppendExtraVariant(extraVariant string) + + // SetRamdiskVariantNeeded sets whether the Ramdisk Variant is needed. + SetRamdiskVariantNeeded(b bool) + + // SetVendorRamdiskVariantNeeded sets whether the Vendor Ramdisk Variant is needed. + SetVendorRamdiskVariantNeeded(b bool) + + // SetRecoveryVariantNeeded sets whether the Recovery Variant is needed. + SetRecoveryVariantNeeded(b bool) + + // SetCoreVariantNeeded sets whether the Core Variant is needed. + SetCoreVariantNeeded(b bool) +} + +var _ ImageMutatableModule = (*Module)(nil) + +func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { + m.CheckVndkProperties(mctx) + MutateImage(mctx, m) +} + +// CheckVndkProperties checks whether the VNDK-related properties are set correctly. +// If properties are not set correctly, results in a module context property error. +func (m *Module) CheckVndkProperties(mctx android.BaseModuleContext) { + vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() + productSpecific := mctx.ProductSpecific() if vndkdep := m.vndkdep; vndkdep != nil { if vndkdep.isVndk() { @@ -277,6 +310,111 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { } } } +} + +func (m *Module) VendorAvailable() bool { + return Bool(m.VendorProperties.Vendor_available) +} + +func (m *Module) OdmAvailable() bool { + return Bool(m.VendorProperties.Odm_available) +} + +func (m *Module) ProductAvailable() bool { + return Bool(m.VendorProperties.Product_available) +} + +func (m *Module) RamdiskAvailable() bool { + return Bool(m.Properties.Ramdisk_available) +} + +func (m *Module) VendorRamdiskAvailable() bool { + return Bool(m.Properties.Vendor_ramdisk_available) +} + +func (m *Module) AndroidModuleBase() *android.ModuleBase { + return &m.ModuleBase +} + +func (m *Module) RecoveryAvailable() bool { + return Bool(m.Properties.Recovery_available) +} + +func (m *Module) ExtraVariants() []string { + return m.Properties.ExtraVariants +} + +func (m *Module) AppendExtraVariant(extraVariant string) { + m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, extraVariant) +} + +func (m *Module) SetRamdiskVariantNeeded(b bool) { + m.Properties.RamdiskVariantNeeded = b +} + +func (m *Module) SetVendorRamdiskVariantNeeded(b bool) { + m.Properties.VendorRamdiskVariantNeeded = b +} + +func (m *Module) SetRecoveryVariantNeeded(b bool) { + m.Properties.RecoveryVariantNeeded = b +} + +func (m *Module) SetCoreVariantNeeded(b bool) { + m.Properties.CoreVariantNeeded = b +} + +func (m *Module) SnapshotVersion(mctx android.BaseModuleContext) string { + if snapshot, ok := m.linker.(snapshotInterface); ok { + return snapshot.version() + } else { + mctx.ModuleErrorf("version is unknown for snapshot prebuilt") + // Should we be panicking here instead? + return "" + } +} + +func (m *Module) KernelHeadersDecorator() bool { + if _, ok := m.linker.(*kernelHeadersDecorator); ok { + return true + } + return false +} + +// MutateImage handles common image mutations for ImageMutatableModule interfaces. +func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { + // Validation check + vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() + productSpecific := mctx.ProductSpecific() + + if m.VendorAvailable() { + if vendorSpecific { + mctx.PropertyErrorf("vendor_available", + "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`") + } + if m.OdmAvailable() { + mctx.PropertyErrorf("vendor_available", + "doesn't make sense at the same time as `odm_available: true`") + } + } + + if m.OdmAvailable() { + if vendorSpecific { + mctx.PropertyErrorf("odm_available", + "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`") + } + } + + if m.ProductAvailable() { + if productSpecific { + mctx.PropertyErrorf("product_available", + "doesn't make sense at the same time as `product_specific: true`") + } + if vendorSpecific { + mctx.PropertyErrorf("product_available", + "cannot provide product variant from a vendor module. Please use `product_specific: true` with `vendor_available: true`") + } + } var coreVariantNeeded bool = false var ramdiskVariantNeeded bool = false @@ -299,18 +437,13 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { productVndkVersion = platformVndkVersion } - _, isLLNDKLibrary := m.linker.(*llndkStubDecorator) - _, isLLNDKHeaders := m.linker.(*llndkHeadersDecorator) - lib := moduleLibraryInterface(m) - hasLLNDKStubs := lib != nil && lib.hasLLNDKStubs() - - if isLLNDKLibrary || isLLNDKHeaders || hasLLNDKStubs { + if m.IsLlndkLibrary() || m.IsLlndkHeaders() || m.HasLlndkStubs() { // This is an LLNDK library. The implementation of the library will be on /system, // and vendor and product variants will be created with LLNDK stubs. // The LLNDK libraries need vendor variants even if there is no VNDK. // The obsolete llndk_library and llndk_headers modules also need the vendor variants // so the cc_library LLNDK stubs can depend on them. - if hasLLNDKStubs { + if m.HasLlndkStubs() { coreVariantNeeded = true } if platformVndkVersion != "" { @@ -327,17 +460,13 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { // If the device isn't compiling against the VNDK, we always // use the core mode. coreVariantNeeded = true - } else if m.isSnapshotPrebuilt() { + } else if m.IsSnapshotPrebuilt() { // Make vendor variants only for the versions in BOARD_VNDK_VERSION and // PRODUCT_EXTRA_VNDK_VERSIONS. - if snapshot, ok := m.linker.(snapshotInterface); ok { - if m.InstallInRecovery() { - recoveryVariantNeeded = true - } else { - vendorVariants = append(vendorVariants, snapshot.version()) - } + if m.InstallInRecovery() { + recoveryVariantNeeded = true } else { - mctx.ModuleErrorf("version is unknown for snapshot prebuilt") + vendorVariants = append(vendorVariants, m.SnapshotVersion(mctx)) } } else if m.HasNonSystemVariants() && !m.IsVndkExt() { // This will be available to /system unless it is product_specific @@ -363,7 +492,7 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { productVariants = append(productVariants, productVndkVersion) } } - } else if vendorSpecific && String(m.Properties.Sdk_version) == "" { + } else if vendorSpecific && m.SdkVersion() == "" { // This will be available in /vendor (or /odm) only // kernel_headers is a special module type whose exported headers @@ -372,7 +501,7 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { // For other modules, we assume that modules under proprietary // paths are compatible for BOARD_VNDK_VERSION. The other modules // are regarded as AOSP, which is PLATFORM_VNDK_VERSION. - if _, ok := m.linker.(*kernelHeadersDecorator); ok { + if m.KernelHeadersDecorator() { vendorVariants = append(vendorVariants, platformVndkVersion, boardVndkVersion, @@ -390,7 +519,7 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { } if boardVndkVersion != "" && productVndkVersion != "" { - if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" { + if coreVariantNeeded && productSpecific && m.SdkVersion() == "" { // The module has "product_specific: true" that does not create core variant. coreVariantNeeded = false productVariants = append(productVariants, productVndkVersion) @@ -402,60 +531,60 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { productVariants = []string{} } - if Bool(m.Properties.Ramdisk_available) { + if m.RamdiskAvailable() { ramdiskVariantNeeded = true } - if m.ModuleBase.InstallInRamdisk() { + if m.AndroidModuleBase().InstallInRamdisk() { ramdiskVariantNeeded = true coreVariantNeeded = false } - if Bool(m.Properties.Vendor_ramdisk_available) { + if m.VendorRamdiskAvailable() { vendorRamdiskVariantNeeded = true } - if m.ModuleBase.InstallInVendorRamdisk() { + if m.AndroidModuleBase().InstallInVendorRamdisk() { vendorRamdiskVariantNeeded = true coreVariantNeeded = false } - if Bool(m.Properties.Recovery_available) { + if m.RecoveryAvailable() { recoveryVariantNeeded = true } - if m.ModuleBase.InstallInRecovery() { + if m.AndroidModuleBase().InstallInRecovery() { recoveryVariantNeeded = true coreVariantNeeded = false } // If using a snapshot, the recovery variant under AOSP directories is not needed, // except for kernel headers, which needs all variants. - if _, ok := m.linker.(*kernelHeadersDecorator); !ok && - !m.isSnapshotPrebuilt() && + if m.KernelHeadersDecorator() && + !m.IsSnapshotPrebuilt() && usingRecoverySnapshot && !isRecoveryProprietaryModule(mctx) { recoveryVariantNeeded = false } for _, variant := range android.FirstUniqueStrings(vendorVariants) { - m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant) + m.AppendExtraVariant(VendorVariationPrefix + variant) } for _, variant := range android.FirstUniqueStrings(productVariants) { - m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant) + m.AppendExtraVariant(ProductVariationPrefix + variant) } - m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded - m.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded - m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded - m.Properties.CoreVariantNeeded = coreVariantNeeded + m.SetRamdiskVariantNeeded(ramdiskVariantNeeded) + m.SetVendorRamdiskVariantNeeded(vendorRamdiskVariantNeeded) + m.SetRecoveryVariantNeeded(recoveryVariantNeeded) + m.SetCoreVariantNeeded(coreVariantNeeded) // Disable the module if no variants are needed. if !ramdiskVariantNeeded && !recoveryVariantNeeded && !coreVariantNeeded && - len(m.Properties.ExtraVariants) == 0 { + len(m.ExtraVariants()) == 0 { m.Disable() } } @@ -472,6 +601,10 @@ func (c *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool return c.Properties.VendorRamdiskVariantNeeded } +func (c *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return false +} + func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return c.Properties.RecoveryVariantNeeded } diff --git a/cc/linkable.go b/cc/linkable.go index 6aa238b24..571a3bb71 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -98,10 +98,24 @@ type LinkableInterface interface { InVendor() bool UseSdk() bool - UseVndk() bool - MustUseVendorVariant() bool + + // IsLlndk returns true for both LLNDK (public) and LLNDK-private libs. IsLlndk() bool + + // IsLlndkPublic returns true only for LLNDK (public) libs. IsLlndkPublic() bool + + // IsLlndkHeaders returns true if this module is an LLNDK headers module. + IsLlndkHeaders() bool + + // IsLlndkLibrary returns true if this module is an LLNDK library module. + IsLlndkLibrary() bool + + // HasLlndkStubs returns true if this module has LLNDK stubs. + HasLlndkStubs() bool + + UseVndk() bool + MustUseVendorVariant() bool IsVndk() bool IsVndkExt() bool IsVndkPrivate() bool @@ -110,6 +124,9 @@ type LinkableInterface interface { HasNonSystemVariants() bool InProduct() bool + // SubName returns the modules SubName, used for image and NDK/SDK variations. + SubName() string + SdkVersion() string MinSdkVersion() string AlwaysSdk() bool @@ -121,6 +138,10 @@ type LinkableInterface interface { SetPreventInstall() // SetHideFromMake sets the HideFromMake property to 'true' for this module. SetHideFromMake() + + // KernelHeadersDecorator returns true if this is a kernel headers decorator module. + // This is specific to cc and should always return false for all other packages. + KernelHeadersDecorator() bool } var ( @@ -152,6 +173,15 @@ func GetImageVariantType(c LinkableInterface) ImageVariantType { } } +// DepTagMakeSuffix returns the makeSuffix value of a particular library dependency tag. +// Returns an empty string if not a library dependency tag. +func DepTagMakeSuffix(depTag blueprint.DependencyTag) string { + if libDepTag, ok := depTag.(libraryDependencyTag); ok { + return libDepTag.makeSuffix + } + return "" +} + // SharedDepTag returns the dependency tag for any C++ shared libraries. func SharedDepTag() blueprint.DependencyTag { return libraryDependencyTag{Kind: sharedLibraryDependency} diff --git a/cc/sabi.go b/cc/sabi.go index 4a1ba3cda..c0eb57cc3 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -141,7 +141,7 @@ func shouldCreateSourceAbiDumpForLibrary(ctx android.BaseModuleContext) bool { } // Don't create ABI dump for prebuilts. - if m.Prebuilt() != nil || m.isSnapshotPrebuilt() { + if m.Prebuilt() != nil || m.IsSnapshotPrebuilt() { return false } diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index af0510272..6d48aed64 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -308,6 +308,10 @@ func (s *snapshot) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) boo return false } +func (s *snapshot) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return false +} + func (s *snapshot) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return false } @@ -559,10 +563,18 @@ func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps Pat return nil } + // Flags specified directly to this module. p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...) p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...) p.libraryDecorator.reexportFlags(p.properties.Export_flags...) + // Flags reexported from dependencies. (e.g. vndk_prebuilt_shared) + p.libraryDecorator.reexportDirs(deps.ReexportedDirs...) + p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...) + p.libraryDecorator.reexportFlags(deps.ReexportedFlags...) + p.libraryDecorator.reexportDeps(deps.ReexportedDeps...) + p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...) + in := android.PathForModuleSrc(ctx, *p.properties.Src) p.unstrippedOutputFile = in diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index 3437d77a4..2f68ccad1 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -173,7 +173,7 @@ func isSnapshotAware(cfg android.DeviceConfig, m *Module, inProprietaryPath bool return false } // the module must be installed in target image - if !apexInfo.IsForPlatform() || m.isSnapshotPrebuilt() || !image.inImage(m)() { + if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.inImage(m)() { return false } // skip kernel_headers which always depend on vendor diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go index 1c3f1b482..66396f749 100644 --- a/cc/vendor_snapshot_test.go +++ b/cc/vendor_snapshot_test.go @@ -424,6 +424,20 @@ func TestVendorSnapshotUse(t *testing.T) { srcs: ["client.cpp"], } + cc_library_shared { + name: "libclient_cfi", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + static_libs: ["libvendor"], + sanitize: { + cfi: true, + }, + srcs: ["client.cpp"], + } + cc_binary { name: "bin_without_snapshot", vendor: true, @@ -492,13 +506,13 @@ func TestVendorSnapshotUse(t *testing.T) { arch: { arm64: { src: "libvndk.a", - export_include_dirs: ["include/libvndk"], }, arm: { src: "libvndk.a", - export_include_dirs: ["include/libvndk"], }, }, + shared_libs: ["libvndk"], + export_shared_lib_headers: ["libvndk"], } vendor_snapshot_shared { @@ -584,10 +598,18 @@ func TestVendorSnapshotUse(t *testing.T) { vendor: true, arch: { arm64: { + cfi: { + src: "libvendor.cfi.a", + export_include_dirs: ["include/libvendor_cfi"], + }, src: "libvendor.a", export_include_dirs: ["include/libvendor"], }, arm: { + cfi: { + src: "libvendor.cfi.a", + export_include_dirs: ["include/libvendor_cfi"], + }, src: "libvendor.a", export_include_dirs: ["include/libvendor"], }, @@ -726,29 +748,31 @@ func TestVendorSnapshotUse(t *testing.T) { depsBp := GatherRequiredDepsForTest(android.Android) mockFS := map[string][]byte{ - "deps/Android.bp": []byte(depsBp), - "framework/Android.bp": []byte(frameworkBp), - "framework/symbol.txt": nil, - "vendor/Android.bp": []byte(vendorProprietaryBp), - "vendor/bin": nil, - "vendor/bin32": nil, - "vendor/bin.cpp": nil, - "vendor/client.cpp": nil, - "vendor/include/libvndk/a.h": nil, - "vendor/include/libvendor/b.h": nil, - "vendor/libc++_static.a": nil, - "vendor/libc++demangle.a": nil, - "vendor/libgcc_striped.a": nil, - "vendor/libvndk.a": nil, - "vendor/libvendor.a": nil, - "vendor/libvendor.so": nil, - "vendor/lib32.a": nil, - "vendor/lib32.so": nil, - "vendor/lib64.a": nil, - "vendor/lib64.so": nil, - "vndk/Android.bp": []byte(vndkBp), - "vndk/include/libvndk/a.h": nil, - "vndk/libvndk.so": nil, + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/symbol.txt": nil, + "vendor/Android.bp": []byte(vendorProprietaryBp), + "vendor/bin": nil, + "vendor/bin32": nil, + "vendor/bin.cpp": nil, + "vendor/client.cpp": nil, + "vendor/include/libvndk/a.h": nil, + "vendor/include/libvendor/b.h": nil, + "vendor/include/libvendor_cfi/c.h": nil, + "vendor/libc++_static.a": nil, + "vendor/libc++demangle.a": nil, + "vendor/libgcc_striped.a": nil, + "vendor/libvndk.a": nil, + "vendor/libvendor.a": nil, + "vendor/libvendor.cfi.a": nil, + "vendor/libvendor.so": nil, + "vendor/lib32.a": nil, + "vendor/lib32.so": nil, + "vendor/lib64.a": nil, + "vendor/lib64.so": nil, + "vndk/Android.bp": []byte(vndkBp), + "vndk/include/libvndk/a.h": nil, + "vndk/libvndk.so": nil, } config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) @@ -766,6 +790,9 @@ func TestVendorSnapshotUse(t *testing.T) { staticVariant := "android_vendor.30_arm64_armv8-a_static" binaryVariant := "android_vendor.30_arm64_armv8-a" + sharedCfiVariant := "android_vendor.30_arm64_armv8-a_shared_cfi" + staticCfiVariant := "android_vendor.30_arm64_armv8-a_static_cfi" + shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared" binary32Variant := "android_vendor.30_arm_armv7-a-neon" @@ -808,9 +835,22 @@ func TestVendorSnapshotUse(t *testing.T) { t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g) } - // bin_without_snapshot uses libvndk.vendor_static.30.arm64 + // libclient_cfi uses libvendor.vendor_static.30.arm64's cfi variant + libclientCfiCcFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("cc").Args["cFlags"] + if !strings.Contains(libclientCfiCcFlags, "-Ivendor/include/libvendor_cfi") { + t.Errorf("flags for libclient_cfi must contain %#v, but was %#v.", + "-Ivendor/include/libvendor_cfi", libclientCfiCcFlags) + } + + libclientCfiLdFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("ld").Args["libFlags"] + libvendorCfiOutputPaths := getOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.30.arm64"}) + if !strings.Contains(libclientCfiLdFlags, libvendorCfiOutputPaths[0].String()) { + t.Errorf("libflags for libclientCfi must contain %#v, but was %#v", libvendorCfiOutputPaths[0], libclientCfiLdFlags) + } + + // bin_without_snapshot uses libvndk.vendor_static.30.arm64 (which reexports vndk's exported headers) binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"] - if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivendor/include/libvndk") { + if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivndk/include/libvndk") { t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.", "-Ivendor/include/libvndk", binWithoutSnapshotCcFlags) } diff --git a/cc/vndk.go b/cc/vndk.go index b7047e92e..1a8a45439 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -609,8 +609,8 @@ func isVndkSnapshotAware(config android.DeviceConfig, m *Module, } // !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants. // !installable: Snapshot only cares about "installable" modules. - // isSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense. - if !m.InVendor() || !m.installable(apexInfo) || m.isSnapshotPrebuilt() { + // IsSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense. + if !m.InVendor() || !m.installable(apexInfo) || m.IsSnapshotPrebuilt() { return nil, "", false } l, ok := m.linker.(snapshotLibraryInterface) diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 431d6214f..1e796ecca 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -23,29 +23,43 @@ import ( "strings" "time" + "android/soong/bp2build" "android/soong/shared" "github.com/google/blueprint/bootstrap" + "github.com/google/blueprint/deptools" "android/soong/android" - "android/soong/bp2build" ) var ( - topDir string - outDir string + topDir string + outDir string + availableEnvFile string + usedEnvFile string + + delveListen string + delvePath string + docFile string bazelQueryViewDir string - delveListen string - delvePath string + bp2buildMarker string ) func init() { + // Flags that make sense in every mode flag.StringVar(&topDir, "top", "", "Top directory of the Android source tree") flag.StringVar(&outDir, "out", "", "Soong output directory (usually $TOP/out/soong)") + flag.StringVar(&availableEnvFile, "available_env", "", "File containing available environment variables") + flag.StringVar(&usedEnvFile, "used_env", "", "File containing used environment variables") + + // Debug flags flag.StringVar(&delveListen, "delve_listen", "", "Delve port to listen on for debugging") flag.StringVar(&delvePath, "delve_path", "", "Path to Delve. Only used if --delve_listen is set") + + // Flags representing various modes soong_build can run in flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output") flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top") + flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit") } func newNameResolver(config android.Config) *android.NameResolver { @@ -75,8 +89,8 @@ func newContext(configuration android.Config, prepareBuildActions bool) *android return ctx } -func newConfig(srcDir, outDir string) android.Config { - configuration, err := android.NewConfig(srcDir, outDir, bootstrap.CmdlineModuleListFile()) +func newConfig(srcDir, outDir string, availableEnv map[string]string) android.Config { + configuration, err := android.NewConfig(srcDir, outDir, bootstrap.CmdlineArgs.ModuleListFile, availableEnv) if err != nil { fmt.Fprintf(os.Stderr, "%s", err) os.Exit(1) @@ -90,21 +104,31 @@ func newConfig(srcDir, outDir string) android.Config { // TODO(cparsons): Don't output any ninja file, as the second pass will overwrite // the incorrect results from the first pass, and file I/O is expensive. func runMixedModeBuild(configuration android.Config, firstCtx *android.Context, extraNinjaDeps []string) { + var firstArgs, secondArgs bootstrap.Args + + firstArgs = bootstrap.CmdlineArgs configuration.SetStopBefore(bootstrap.StopBeforeWriteNinja) - bootstrap.Main(firstCtx.Context, configuration, false, extraNinjaDeps...) + bootstrap.RunBlueprint(firstArgs, firstCtx.Context, configuration, extraNinjaDeps...) + // Invoke bazel commands and save results for second pass. if err := configuration.BazelContext.InvokeBazel(); err != nil { fmt.Fprintf(os.Stderr, "%s", err) os.Exit(1) } // Second pass: Full analysis, using the bazel command results. Output ninja file. - secondPassConfig, err := android.ConfigForAdditionalRun(configuration) + secondConfig, err := android.ConfigForAdditionalRun(configuration) if err != nil { fmt.Fprintf(os.Stderr, "%s", err) os.Exit(1) } - secondCtx := newContext(secondPassConfig, true) - bootstrap.Main(secondCtx.Context, secondPassConfig, false, extraNinjaDeps...) + secondCtx := newContext(secondConfig, true) + secondArgs = bootstrap.CmdlineArgs + ninjaDeps := bootstrap.RunBlueprint(secondArgs, secondCtx.Context, secondConfig, extraNinjaDeps...) + err = deptools.WriteDepFile(shared.JoinPath(topDir, secondArgs.DepFile), secondArgs.OutFile, ninjaDeps) + if err != nil { + fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", secondArgs.DepFile, err) + os.Exit(1) + } } // Run the code-generation phase to convert BazelTargetModules to BUILD files. @@ -119,7 +143,8 @@ func runQueryView(configuration android.Config, ctx *android.Context) { func runSoongDocs(configuration android.Config, extraNinjaDeps []string) { ctx := newContext(configuration, false) - bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...) + soongDocsArgs := bootstrap.CmdlineArgs + bootstrap.RunBlueprint(soongDocsArgs, ctx.Context, configuration, extraNinjaDeps...) if err := writeDocs(ctx, configuration, docFile); err != nil { fmt.Fprintf(os.Stderr, "%s", err) os.Exit(1) @@ -147,40 +172,78 @@ func writeJsonModuleGraph(configuration android.Config, ctx *android.Context, pa writeFakeNinjaFile(extraNinjaDeps, configuration.BuildDir()) } -func doChosenActivity(configuration android.Config, extraNinjaDeps []string) { - bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES") +func doChosenActivity(configuration android.Config, extraNinjaDeps []string) string { + bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES") || bp2buildMarker != "" mixedModeBuild := configuration.BazelContext.BazelEnabled() generateQueryView := bazelQueryViewDir != "" jsonModuleFile := configuration.Getenv("SOONG_DUMP_JSON_MODULE_GRAPH") + blueprintArgs := bootstrap.CmdlineArgs prepareBuildActions := !generateQueryView && jsonModuleFile == "" - if bazelConversionRequested { // Run the alternate pipeline of bp2build mutators and singleton to convert // Blueprint to BUILD files before everything else. runBp2Build(configuration, extraNinjaDeps) - return + if bp2buildMarker != "" { + return bp2buildMarker + } else { + return bootstrap.CmdlineArgs.OutFile + } } ctx := newContext(configuration, prepareBuildActions) if mixedModeBuild { runMixedModeBuild(configuration, ctx, extraNinjaDeps) } else { - bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...) + ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, ctx.Context, configuration, extraNinjaDeps...) + err := deptools.WriteDepFile(shared.JoinPath(topDir, blueprintArgs.DepFile), blueprintArgs.OutFile, ninjaDeps) + if err != nil { + fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", blueprintArgs.DepFile, err) + os.Exit(1) + } } // Convert the Soong module graph into Bazel BUILD files. if generateQueryView { runQueryView(configuration, ctx) - return + return bootstrap.CmdlineArgs.OutFile // TODO: This is a lie } if jsonModuleFile != "" { writeJsonModuleGraph(configuration, ctx, jsonModuleFile, extraNinjaDeps) - return + return bootstrap.CmdlineArgs.OutFile // TODO: This is a lie } writeMetrics(configuration) + return bootstrap.CmdlineArgs.OutFile +} + +// soong_ui dumps the available environment variables to +// soong.environment.available . Then soong_build itself is run with an empty +// environment so that the only way environment variables can be accessed is +// using Config, which tracks access to them. + +// At the end of the build, a file called soong.environment.used is written +// containing the current value of all used environment variables. The next +// time soong_ui is run, it checks whether any environment variables that was +// used had changed and if so, it deletes soong.environment.used to cause a +// rebuild. +// +// The dependency of build.ninja on soong.environment.used is declared in +// build.ninja.d +func parseAvailableEnv() map[string]string { + if availableEnvFile == "" { + fmt.Fprintf(os.Stderr, "--available_env not set\n") + os.Exit(1) + } + + result, err := shared.EnvFromFile(shared.JoinPath(topDir, availableEnvFile)) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading available environment file '%s': %s\n", availableEnvFile, err) + os.Exit(1) + } + + return result } func main() { @@ -188,15 +251,15 @@ func main() { shared.ReexecWithDelveMaybe(delveListen, delvePath) android.InitSandbox(topDir) - android.InitEnvironment(shared.JoinPath(topDir, outDir, "soong.environment.available")) - usedVariablesFile := shared.JoinPath(outDir, "soong.environment.used") + availableEnv := parseAvailableEnv() + // The top-level Blueprints file is passed as the first argument. srcDir := filepath.Dir(flag.Arg(0)) - configuration := newConfig(srcDir, outDir) + configuration := newConfig(srcDir, outDir, availableEnv) extraNinjaDeps := []string{ configuration.ProductVariablesFileName, - shared.JoinPath(outDir, "soong.environment.used"), + usedEnvFile, } if configuration.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" { @@ -214,37 +277,37 @@ func main() { // because that is done from within the actual builds as a Ninja action and // thus it would overwrite the actual used variables file so this is // special-cased. + // TODO: Fix this by not passing --used_env to the soong_docs invocation runSoongDocs(configuration, extraNinjaDeps) return } - doChosenActivity(configuration, extraNinjaDeps) - writeUsedVariablesFile(shared.JoinPath(topDir, usedVariablesFile), configuration) + finalOutputFile := doChosenActivity(configuration, extraNinjaDeps) + writeUsedEnvironmentFile(configuration, finalOutputFile) } -func writeUsedVariablesFile(path string, configuration android.Config) { +func writeUsedEnvironmentFile(configuration android.Config, finalOutputFile string) { + if usedEnvFile == "" { + return + } + + path := shared.JoinPath(topDir, usedEnvFile) data, err := shared.EnvFileContents(configuration.EnvDeps()) if err != nil { - fmt.Fprintf(os.Stderr, "error writing used variables file %s: %s\n", path, err) + fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err) os.Exit(1) } err = ioutil.WriteFile(path, data, 0666) if err != nil { - fmt.Fprintf(os.Stderr, "error writing used variables file %s: %s\n", path, err) + fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err) os.Exit(1) } - // Touch the output Ninja file so that it's not older than the file we just + // Touch the output file so that it's not older than the file we just // wrote. We can't write the environment file earlier because one an access // new environment variables while writing it. - outputNinjaFile := shared.JoinPath(topDir, bootstrap.CmdlineOutFile()) - currentTime := time.Now().Local() - err = os.Chtimes(outputNinjaFile, currentTime, currentTime) - if err != nil { - fmt.Fprintf(os.Stderr, "error touching output file %s: %s\n", outputNinjaFile, err) - os.Exit(1) - } + touch(shared.JoinPath(topDir, finalOutputFile)) } // Workarounds to support running bp2build in a clean AOSP checkout with no @@ -270,6 +333,27 @@ func writeFakeNinjaFile(extraNinjaDeps []string, buildDir string) { 0666) } +func touch(path string) { + f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + fmt.Fprintf(os.Stderr, "Error touching '%s': %s\n", path, err) + os.Exit(1) + } + + err = f.Close() + if err != nil { + fmt.Fprintf(os.Stderr, "Error touching '%s': %s\n", path, err) + os.Exit(1) + } + + currentTime := time.Now().Local() + err = os.Chtimes(path, currentTime, currentTime) + if err != nil { + fmt.Fprintf(os.Stderr, "error touching '%s': %s\n", path, err) + os.Exit(1) + } +} + // Run Soong in the bp2build mode. This creates a standalone context that registers // an alternate pipeline of mutators and singletons specifically for generating // Bazel BUILD files instead of Ninja files. @@ -277,17 +361,18 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { // Register an alternate set of singletons and mutators for bazel // conversion for Bazel conversion. bp2buildCtx := android.NewContext(configuration) - bp2buildCtx.RegisterForBazelConversion() - // No need to generate Ninja build rules/statements from Modules and Singletons. - configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions) + // Propagate "allow misssing dependencies" bit. This is normally set in + // newContext(), but we create bp2buildCtx without calling that method. + bp2buildCtx.SetAllowMissingDependencies(configuration.AllowMissingDependencies()) bp2buildCtx.SetNameInterface(newNameResolver(configuration)) + bp2buildCtx.RegisterForBazelConversion() // The bp2build process is a purely functional process that only depends on // Android.bp files. It must not depend on the values of per-build product // configurations or variables, since those will generate different BUILD // files based on how the user has configured their tree. - bp2buildCtx.SetModuleListFile(bootstrap.CmdlineModuleListFile()) + bp2buildCtx.SetModuleListFile(bootstrap.CmdlineArgs.ModuleListFile) modulePaths, err := bp2buildCtx.ListModulePaths(configuration.SrcDir()) if err != nil { panic(err) @@ -295,10 +380,25 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { extraNinjaDeps = append(extraNinjaDeps, modulePaths...) + // No need to generate Ninja build rules/statements from Modules and Singletons. + configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions) + // Run the loading and analysis pipeline to prepare the graph of regular // Modules parsed from Android.bp files, and the BazelTargetModules mapped // from the regular Modules. - bootstrap.Main(bp2buildCtx.Context, configuration, false, extraNinjaDeps...) + blueprintArgs := bootstrap.CmdlineArgs + ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bp2buildCtx.Context, configuration, extraNinjaDeps...) + + for _, globPath := range bp2buildCtx.Globs() { + ninjaDeps = append(ninjaDeps, globPath.FileListFile(configuration.BuildDir())) + } + + depFile := bp2buildMarker + ".d" + err = deptools.WriteDepFile(shared.JoinPath(topDir, depFile), bp2buildMarker, ninjaDeps) + if err != nil { + fmt.Fprintf(os.Stderr, "Cannot write depfile '%s': %s\n", depFile, err) + os.Exit(1) + } // Run the code-generation phase to convert BazelTargetModules to BUILD files // and print conversion metrics to the user. @@ -311,5 +411,9 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) { metrics.Print() extraNinjaDeps = append(extraNinjaDeps, codegenContext.AdditionalNinjaDeps()...) - writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir()) + if bp2buildMarker != "" { + touch(shared.JoinPath(topDir, bp2buildMarker)) + } else { + writeFakeNinjaFile(extraNinjaDeps, codegenContext.Config().BuildDir()) + } } diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 6291325f4..3204e706e 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -29,6 +29,7 @@ package etc import ( "fmt" + "strings" "github.com/google/blueprint/proptools" @@ -47,6 +48,7 @@ func init() { func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory) ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory) + ctx.RegisterModuleType("prebuilt_root", PrebuiltRootFactory) ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory) ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory) ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory) @@ -60,14 +62,6 @@ type prebuiltEtcProperties struct { // Source file of this prebuilt. Can reference a genrule type module with the ":module" syntax. Src *string `android:"path,arch_variant"` - // Optional subdirectory under which this file is installed into, cannot be specified with - // relative_install_path, prefer relative_install_path. - Sub_dir *string `android:"arch_variant"` - - // Optional subdirectory under which this file is installed into, cannot be specified with - // sub_dir. - Relative_install_path *string `android:"arch_variant"` - // Optional name for the installed file. If unspecified, name of the module is used as the file // name. Filename *string `android:"arch_variant"` @@ -90,6 +84,13 @@ type prebuiltEtcProperties struct { // the recovery variant instead. Vendor_ramdisk_available *bool + // Make this module available when building for debug ramdisk. + // On device without a dedicated recovery partition, the module is only + // available after switching root into + // /first_stage_ramdisk. To expose the module before switching root, install + // the recovery variant instead. + Debug_ramdisk_available *bool + // Make this module available when building for recovery. Recovery_available *bool @@ -100,6 +101,16 @@ type prebuiltEtcProperties struct { Symlinks []string `android:"arch_variant"` } +type prebuiltSubdirProperties struct { + // Optional subdirectory under which this file is installed into, cannot be specified with + // relative_install_path, prefer relative_install_path. + Sub_dir *string `android:"arch_variant"` + + // Optional subdirectory under which this file is installed into, cannot be specified with + // sub_dir. + Relative_install_path *string `android:"arch_variant"` +} + type PrebuiltEtcModule interface { android.Module @@ -117,7 +128,8 @@ type PrebuiltEtcModule interface { type PrebuiltEtc struct { android.ModuleBase - properties prebuiltEtcProperties + properties prebuiltEtcProperties + subdirProperties prebuiltSubdirProperties sourceFilePath android.Path outputFilePath android.OutputPath @@ -154,6 +166,18 @@ func (p *PrebuiltEtc) InstallInVendorRamdisk() bool { return p.inVendorRamdisk() } +func (p *PrebuiltEtc) inDebugRamdisk() bool { + return p.ModuleBase.InDebugRamdisk() || p.ModuleBase.InstallInDebugRamdisk() +} + +func (p *PrebuiltEtc) onlyInDebugRamdisk() bool { + return p.ModuleBase.InstallInDebugRamdisk() +} + +func (p *PrebuiltEtc) InstallInDebugRamdisk() bool { + return p.inDebugRamdisk() +} + func (p *PrebuiltEtc) inRecovery() bool { return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery() } @@ -172,7 +196,7 @@ func (p *PrebuiltEtc) ImageMutatorBegin(ctx android.BaseModuleContext) {} func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool { return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk() && - !p.ModuleBase.InstallInVendorRamdisk() + !p.ModuleBase.InstallInVendorRamdisk() && !p.ModuleBase.InstallInDebugRamdisk() } func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { @@ -183,6 +207,10 @@ func (p *PrebuiltEtc) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) return proptools.Bool(p.properties.Vendor_ramdisk_available) || p.ModuleBase.InstallInVendorRamdisk() } +func (p *PrebuiltEtc) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(p.properties.Debug_ramdisk_available) || p.ModuleBase.InstallInDebugRamdisk() +} + func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery() } @@ -224,10 +252,10 @@ func (p *PrebuiltEtc) OutputFiles(tag string) (android.Paths, error) { } func (p *PrebuiltEtc) SubDir() string { - if subDir := proptools.String(p.properties.Sub_dir); subDir != "" { + if subDir := proptools.String(p.subdirProperties.Sub_dir); subDir != "" { return subDir } - return proptools.String(p.properties.Relative_install_path) + return proptools.String(p.subdirProperties.Relative_install_path) } func (p *PrebuiltEtc) BaseDir() string { @@ -263,8 +291,13 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { } p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath + if strings.Contains(filename, "/") { + ctx.PropertyErrorf("filename", "filename cannot contain separator '/'") + return + } + // Check that `sub_dir` and `relative_install_path` are not set at the same time. - if p.properties.Sub_dir != nil && p.properties.Relative_install_path != nil { + if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil { ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir") } @@ -303,6 +336,9 @@ func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries { if p.inVendorRamdisk() && !p.onlyInVendorRamdisk() { nameSuffix = ".vendor_ramdisk" } + if p.inDebugRamdisk() && !p.onlyInDebugRamdisk() { + nameSuffix = ".debug_ramdisk" + } if p.inRecovery() && !p.onlyInRecovery() { nameSuffix = ".recovery" } @@ -330,6 +366,12 @@ func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries { func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) { p.installDirBase = dirBase p.AddProperties(&p.properties) + p.AddProperties(&p.subdirProperties) +} + +func InitPrebuiltRootModule(p *PrebuiltEtc) { + p.installDirBase = "." + p.AddProperties(&p.properties) } // prebuilt_etc is for a prebuilt artifact that is installed in @@ -352,6 +394,16 @@ func PrebuiltEtcHostFactory() android.Module { return module } +// prebuilt_root is for a prebuilt artifact that is installed in +// <partition>/ directory. Can't have any sub directories. +func PrebuiltRootFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltRootModule(module) + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + return module +} + // prebuilt_usr_share is for a prebuilt artifact that is installed in // <partition>/usr/share/<sub_dir> directory. func PrebuiltUserShareFactory() android.Module { diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index 9c3db3bfb..fdb564873 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -179,6 +179,30 @@ func TestPrebuiltEtcHost(t *testing.T) { } } +func TestPrebuiltRootInstallDirPath(t *testing.T) { + result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` + prebuilt_root { + name: "foo.conf", + src: "foo.conf", + filename: "foo.conf", + } + `) + + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) + expected := "out/soong/target/product/test_device/system" + android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) +} + +func TestPrebuiltRootInstallDirPathValidate(t *testing.T) { + prepareForPrebuiltEtcTest.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("filename cannot contain separator")).RunTestWithBp(t, ` + prebuilt_root { + name: "foo.conf", + src: "foo.conf", + filename: "foo/bar.conf", + } + `) +} + func TestPrebuiltUserShareInstallDirPath(t *testing.T) { result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` prebuilt_usr_share { diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go index f823387b0..3f16c0d71 100644 --- a/filesystem/vbmeta.go +++ b/filesystem/vbmeta.go @@ -110,6 +110,9 @@ func (v *vbmeta) partitionName() string { return proptools.StringDefault(v.properties.Partition_name, v.BaseModuleName()) } +// See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE +const vbmetaMaxSize = 64 * 1024 + func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { extractedPublicKeys := v.extractPublicKeys(ctx) @@ -172,6 +175,13 @@ func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { } cmd.FlagWithOutput("--output ", v.output) + + // libavb expects to be able to read the maximum vbmeta size, so we must provide a partition + // which matches this or the read will fail. + builder.Command().Text("truncate"). + FlagWithArg("-s ", strconv.Itoa(vbmetaMaxSize)). + Output(v.output) + builder.Build("vbmeta", fmt.Sprintf("vbmeta %s", ctx.ModuleName())) v.installDir = android.PathForModuleInstall(ctx, "etc") diff --git a/genrule/genrule.go b/genrule/genrule.go index d07b00253..e6a5ab97a 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -626,6 +626,7 @@ func (x noopImageInterface) ImageMutatorBegin(android.BaseModuleContext) func (x noopImageInterface) CoreVariantNeeded(android.BaseModuleContext) bool { return false } func (x noopImageInterface) RamdiskVariantNeeded(android.BaseModuleContext) bool { return false } func (x noopImageInterface) VendorRamdiskVariantNeeded(android.BaseModuleContext) bool { return false } +func (x noopImageInterface) DebugRamdiskVariantNeeded(android.BaseModuleContext) bool { return false } func (x noopImageInterface) RecoveryVariantNeeded(android.BaseModuleContext) bool { return false } func (x noopImageInterface) ExtraImageVariations(ctx android.BaseModuleContext) []string { return nil } func (x noopImageInterface) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { diff --git a/java/aar.go b/java/aar.go index a122a94cb..04727e4b9 100644 --- a/java/aar.go +++ b/java/aar.go @@ -218,7 +218,7 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte linkDeps = append(linkDeps, assetDeps...) // SDK version flags - minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } @@ -609,6 +609,9 @@ type AARImport struct { hideApexVariantFromMake bool aarPath android.Path + + sdkVersion android.SdkSpec + minSdkVersion android.SdkSpec } var _ android.OutputFileProducer = (*AARImport)(nil) @@ -625,23 +628,23 @@ func (a *AARImport) OutputFiles(tag string) (android.Paths, error) { } } -func (a *AARImport) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(a.properties.Sdk_version)) +func (a *AARImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version)) } func (a *AARImport) SystemModules() string { return "" } -func (a *AARImport) MinSdkVersion() android.SdkSpec { +func (a *AARImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { if a.properties.Min_sdk_version != nil { - return android.SdkSpecFrom(*a.properties.Min_sdk_version) + return android.SdkSpecFrom(ctx, *a.properties.Min_sdk_version) } - return a.SdkVersion() + return a.SdkVersion(ctx) } -func (a *AARImport) TargetSdkVersion() android.SdkSpec { - return a.SdkVersion() +func (a *AARImport) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return a.SdkVersion(ctx) } func (a *AARImport) javaVersion() string { @@ -727,6 +730,9 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { return } + a.sdkVersion = a.SdkVersion(ctx) + a.minSdkVersion = a.MinSdkVersion(ctx) + a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() aarName := ctx.ModuleName() + ".aar" diff --git a/java/android_manifest.go b/java/android_manifest.go index 8510f30dd..331f941ec 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -51,7 +51,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext if isLibrary { args = append(args, "--library") } else { - minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersion(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersion(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } @@ -87,7 +87,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext args = append(args, "--logging-parent", loggingParent) } var deps android.Paths - targetSdkVersion, err := sdkContext.TargetSdkVersion().EffectiveVersionString(ctx) + targetSdkVersion, err := sdkContext.TargetSdkVersion(ctx).EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid targetSdkVersion: %s", err) } @@ -96,7 +96,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext deps = append(deps, ApiFingerprintPath(ctx)) } - minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } diff --git a/java/androidmk.go b/java/androidmk.go index 75661a7a5..4e594a2fa 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -106,7 +106,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if len(library.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled) } - entries.SetString("LOCAL_SDK_VERSION", library.SdkVersion().Raw) + entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion.String()) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar) entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile) @@ -205,7 +205,7 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { } entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion()) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String()) entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem()) }, }, @@ -255,7 +255,7 @@ func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags) entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile) entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.SdkVersion().Raw) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String()) }, }, }} diff --git a/java/app.go b/java/app.go index 04406e734..5695022f9 100755 --- a/java/app.go +++ b/java/app.go @@ -213,7 +213,7 @@ func (c Certificate) AndroidMkString() string { func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { a.Module.deps(ctx) - if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion().Specified() { + if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion(ctx).Specified() { ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared") } @@ -222,7 +222,7 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { a.aapt.deps(ctx, sdkDep) } - usesSDK := a.SdkVersion().Specified() && a.SdkVersion().Kind != android.SdkCorePlatform + usesSDK := a.SdkVersion(ctx).Specified() && a.SdkVersion(ctx).Kind != android.SdkCorePlatform if usesSDK && Bool(a.appProperties.Jni_uses_sdk_apis) { ctx.PropertyErrorf("jni_uses_sdk_apis", @@ -279,14 +279,14 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if a.Updatable() { - if !a.SdkVersion().Stable() { - ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion()) + if !a.SdkVersion(ctx).Stable() { + ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion(ctx)) } if String(a.deviceProperties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") } - if minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx); err == nil { + if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil { a.checkJniLibsSdkVersion(ctx, minSdkVersion) android.CheckMinSdkVersion(a, ctx, minSdkVersion) } else { @@ -314,7 +314,7 @@ func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVer // The domain of cc.sdk_version is "current" and <number> // We can rely on android.SdkSpec to convert it to <number> so that "current" is // handled properly regardless of sdk finalization. - jniSdkVersion, err := android.SdkSpecFrom(dep.SdkVersion()).EffectiveVersion(ctx) + jniSdkVersion, err := android.SdkSpecFrom(ctx, dep.SdkVersion()).EffectiveVersion(ctx) if err != nil || minSdkVersion.LessThan(jniSdkVersion) { ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)", dep.SdkVersion(), minSdkVersion, ctx.ModuleName()) @@ -327,9 +327,9 @@ func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVer // Returns true if the native libraries should be stored in the APK uncompressed and the // extractNativeLibs application flag should be set to false in the manifest. func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool { - minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx) + minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx) if err != nil { - ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(), err) + ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(ctx), err) } apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) @@ -381,7 +381,7 @@ func (a *AndroidApp) renameResourcesPackage() bool { func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { usePlatformAPI := proptools.Bool(a.Module.deviceProperties.Platform_apis) - if ctx.Module().(android.SdkContext).SdkVersion().Kind == android.SdkModule { + if ctx.Module().(android.SdkContext).SdkVersion(ctx).Kind == android.SdkModule { usePlatformAPI = true } a.aapt.usesNonSdkApis = usePlatformAPI @@ -724,8 +724,8 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } type appDepsInterface interface { - SdkVersion() android.SdkSpec - MinSdkVersion() android.SdkSpec + SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec + MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec RequiresStableAPIs(ctx android.BaseModuleContext) bool } @@ -738,8 +738,8 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, seenModulePaths := make(map[string]bool) if checkNativeSdkVersion { - checkNativeSdkVersion = app.SdkVersion().Specified() && - app.SdkVersion().Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) + checkNativeSdkVersion = app.SdkVersion(ctx).Specified() && + app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) } ctx.WalkDeps(func(module android.Module, parent android.Module) bool { @@ -829,12 +829,16 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { depsInfo[depName] = info } else { toMinSdkVersion := "(no version)" - if m, ok := to.(interface{ MinSdkVersion() string }); ok { - if v := m.MinSdkVersion(); v != "" { - toMinSdkVersion = v + if m, ok := to.(interface { + MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec + }); ok { + if v := m.MinSdkVersion(ctx); !v.ApiLevel.IsNone() { + toMinSdkVersion = v.ApiLevel.String() } - } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok { - if v := m.MinSdkVersionString(); v != "" { + } else if m, ok := to.(interface{ MinSdkVersion() string }); ok { + // TODO(b/175678607) eliminate the use of MinSdkVersion returning + // string + if v := m.MinSdkVersion(); v != "" { toMinSdkVersion = v } } @@ -848,7 +852,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { return true }) - a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersionString(), depsInfo) + a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depsInfo) } func (a *AndroidApp) Updatable() bool { diff --git a/java/app_import.go b/java/app_import.go index 32cec2309..839051ea8 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -394,12 +394,12 @@ func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ androi return false } -func (a *AndroidAppImport) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom("") +func (a *AndroidAppImport) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecPrivate } -func (a *AndroidAppImport) MinSdkVersion() android.SdkSpec { - return android.SdkSpecFrom("") +func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecPrivate } var _ android.ApexModule = (*AndroidAppImport)(nil) diff --git a/java/base.go b/java/base.go index 9bc0738e6..19c85cd75 100644 --- a/java/base.go +++ b/java/base.go @@ -370,10 +370,13 @@ type Module struct { modulePaths []string hideApexVariantFromMake bool + + sdkVersion android.SdkSpec + minSdkVersion android.SdkSpec } -func (j *Module) CheckStableSdkVersion() error { - sdkVersion := j.SdkVersion() +func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error { + sdkVersion := j.SdkVersion(ctx) if sdkVersion.Stable() { return nil } @@ -393,7 +396,7 @@ func (j *Module) CheckStableSdkVersion() error { func (j *Module) checkSdkVersions(ctx android.ModuleContext) { if j.RequiresStableAPIs(ctx) { if sc, ok := ctx.Module().(android.SdkContext); ok { - if !sc.SdkVersion().Specified() { + if !sc.SdkVersion(ctx).Specified() { ctx.PropertyErrorf("sdk_version", "sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).") } @@ -418,7 +421,7 @@ func (j *Module) checkSdkVersions(ctx android.ModuleContext) { func (j *Module) checkPlatformAPI(ctx android.ModuleContext) { if sc, ok := ctx.Module().(android.SdkContext); ok { usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis) - sdkVersionSpecified := sc.SdkVersion().Specified() + sdkVersionSpecified := sc.SdkVersion(ctx).Specified() if usePlatformAPI && sdkVersionSpecified { ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.") } else if !usePlatformAPI && !sdkVersionSpecified { @@ -512,30 +515,30 @@ func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool { return false } -func (j *Module) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(j.deviceProperties.Sdk_version)) +func (j *Module) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(j.deviceProperties.Sdk_version)) } func (j *Module) SystemModules() string { return proptools.String(j.deviceProperties.System_modules) } -func (j *Module) MinSdkVersion() android.SdkSpec { +func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { if j.deviceProperties.Min_sdk_version != nil { - return android.SdkSpecFrom(*j.deviceProperties.Min_sdk_version) + return android.SdkSpecFrom(ctx, *j.deviceProperties.Min_sdk_version) } - return j.SdkVersion() + return j.SdkVersion(ctx) } -func (j *Module) TargetSdkVersion() android.SdkSpec { - if j.deviceProperties.Target_sdk_version != nil { - return android.SdkSpecFrom(*j.deviceProperties.Target_sdk_version) - } - return j.SdkVersion() +func (j *Module) MinSdkVersionString() string { + return j.minSdkVersion.Raw } -func (j *Module) MinSdkVersionString() string { - return j.MinSdkVersion().ApiLevel.String() +func (j *Module) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + if j.deviceProperties.Target_sdk_version != nil { + return android.SdkSpecFrom(ctx, *j.deviceProperties.Target_sdk_version) + } + return j.SdkVersion(ctx) } func (j *Module) AvailableFor(what string) bool { @@ -1209,7 +1212,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } // Dex compilation var dexOutputFile android.OutputPath - dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName) if ctx.Failed() { return } @@ -1267,9 +1270,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.linter.srcJars = srcJars j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...) j.linter.classes = j.implementationJarFile - j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion()) - j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion()) - j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion()) + j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion(ctx)) + j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion(ctx)) + j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion(ctx)) j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() { @@ -1471,7 +1474,7 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu // Implements android.ApexModule func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - sdkSpec := j.MinSdkVersion() + sdkSpec := j.MinSdkVersion(ctx) if !sdkSpec.Specified() { return fmt.Errorf("min_sdk_version is not specified") } @@ -1551,10 +1554,10 @@ func (lt sdkLinkType) rank() int { type moduleWithSdkDep interface { android.Module - getSdkLinkType(name string) (ret sdkLinkType, stubs bool) + getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) } -func (m *Module) getSdkLinkType(name string) (ret sdkLinkType, stubs bool) { +func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) { switch name { case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs", "stub-annotations", "private-stub-annotations-jar", @@ -1576,7 +1579,7 @@ func (m *Module) getSdkLinkType(name string) (ret sdkLinkType, stubs bool) { return linkType, true } - ver := m.SdkVersion() + ver := m.SdkVersion(ctx) switch ver.Kind { case android.SdkCore: return javaCore, false @@ -1606,11 +1609,11 @@ func (j *Module) checkSdkLinkType( return } - myLinkType, stubs := j.getSdkLinkType(ctx.ModuleName()) + myLinkType, stubs := j.getSdkLinkType(ctx, ctx.ModuleName()) if stubs { return } - depLinkType, _ := dep.getSdkLinkType(ctx.OtherModuleName(dep)) + depLinkType, _ := dep.getSdkLinkType(ctx, ctx.OtherModuleName(dep)) if myLinkType.rank() < depLinkType.rank() { ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+ @@ -1638,7 +1641,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } - sdkLinkType, _ := j.getSdkLinkType(ctx.ModuleName()) + sdkLinkType, _ := j.getSdkLinkType(ctx, ctx.ModuleName()) ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) @@ -1656,7 +1659,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: - deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...) + deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } diff --git a/java/droiddoc.go b/java/droiddoc.go index e527d59bc..01c0f16ff 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -261,20 +261,20 @@ func JavadocHostFactory() android.Module { var _ android.OutputFileProducer = (*Javadoc)(nil) -func (j *Javadoc) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(j.properties.Sdk_version)) +func (j *Javadoc) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version)) } func (j *Javadoc) SystemModules() string { return proptools.String(j.properties.System_modules) } -func (j *Javadoc) MinSdkVersion() android.SdkSpec { - return j.SdkVersion() +func (j *Javadoc) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return j.SdkVersion(ctx) } -func (j *Javadoc) TargetSdkVersion() android.SdkSpec { - return j.SdkVersion() +func (j *Javadoc) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return j.SdkVersion(ctx) } func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) { @@ -386,7 +386,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { } case libTag: if dep, ok := module.(SdkLibraryDependency); ok { - deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...) + deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) deps.classpath = append(deps.classpath, dep.HeaderJars...) diff --git a/java/hiddenapi.go b/java/hiddenapi.go index 208ced769..3ecb9772a 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -111,6 +111,13 @@ type hiddenAPIIntf interface { var _ hiddenAPIIntf = (*hiddenAPI)(nil) +// hiddenAPISupportingModule is the interface that is implemented by any module that supports +// contributing to the hidden API processing. +type hiddenAPISupportingModule interface { + android.Module + hiddenAPIIntf +} + // Initialize the hiddenapi structure func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, configurationName string) { // If hiddenapi processing is disabled treat this as inactive. diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 6ba5f35bc..ed0b72250 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -24,7 +24,6 @@ func init() { func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) { ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) - ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory) } var PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents) @@ -116,7 +115,7 @@ func hiddenAPISingletonFactory() android.Singleton { } type hiddenAPISingleton struct { - flags, metadata android.Path + flags android.Path } // hiddenAPI singleton rules @@ -138,30 +137,25 @@ func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" { h.flags = prebuiltFlagsRule(ctx) + prebuiltIndexRule(ctx) return } // These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them. if ctx.Config().FrameworksBaseDirExists(ctx) { h.flags = flagsRule(ctx) - h.metadata = metadataRule(ctx) } else { h.flags = emptyFlagsRule(ctx) } } // Export paths to Make. INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/. -// Both paths are used to call dist-for-goals. func (h *hiddenAPISingleton) MakeVars(ctx android.MakeVarsContext) { if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { return } ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", h.flags.String()) - - if h.metadata != nil { - ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", h.metadata.String()) - } } // stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image @@ -321,6 +315,17 @@ func prebuiltFlagsRule(ctx android.SingletonContext) android.Path { return outputPath } +func prebuiltIndexRule(ctx android.SingletonContext) { + outputPath := hiddenAPISingletonPaths(ctx).index + inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv") + + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: outputPath, + Input: inputPath, + }) +} + // flagsRule is a placeholder that simply returns the location of the file, the generation of the // ninja rules is done in generateHiddenAPIBuildActions. func flagsRule(ctx android.SingletonContext) android.Path { @@ -343,34 +348,6 @@ func emptyFlagsRule(ctx android.SingletonContext) android.Path { return outputPath } -// metadataRule creates a rule to build hiddenapi-unsupported.csv out of the metadata.csv files generated for boot image -// modules. -func metadataRule(ctx android.SingletonContext) android.Path { - var metadataCSV android.Paths - - ctx.VisitAllModules(func(module android.Module) { - if h, ok := module.(hiddenAPIIntf); ok { - if csv := h.metadataCSV(); csv != nil { - metadataCSV = append(metadataCSV, csv) - } - } - }) - - rule := android.NewRuleBuilder(pctx, ctx) - - outputPath := hiddenAPISingletonPaths(ctx).metadata - - rule.Command(). - BuiltTool("merge_csv"). - Flag("--key_field signature"). - FlagWithOutput("--output=", outputPath). - Inputs(metadataCSV) - - rule.Build("hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata") - - return outputPath -} - // commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different. It // also marks the rule as restat and marks the tempPath as a temporary file that should not be considered an output of // the rule. @@ -388,60 +365,3 @@ func commitChangeForRestat(rule *android.RuleBuilder, tempPath, outputPath andro Text("fi"). Text(")") } - -func hiddenAPIIndexSingletonFactory() android.Singleton { - return &hiddenAPIIndexSingleton{} -} - -type hiddenAPIIndexSingleton struct { - index android.Path -} - -func (h *hiddenAPIIndexSingleton) GenerateBuildActions(ctx android.SingletonContext) { - // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { - return - } - - if ctx.Config().PrebuiltHiddenApiDir(ctx) != "" { - outputPath := hiddenAPISingletonPaths(ctx).index - inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-index.csv") - - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Output: outputPath, - Input: inputPath, - }) - - h.index = outputPath - return - } - - indexes := android.Paths{} - ctx.VisitAllModules(func(module android.Module) { - if h, ok := module.(hiddenAPIIntf); ok { - if h.indexCSV() != nil { - indexes = append(indexes, h.indexCSV()) - } - } - }) - - rule := android.NewRuleBuilder(pctx, ctx) - rule.Command(). - BuiltTool("merge_csv"). - Flag("--key_field signature"). - FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties"). - FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index). - Inputs(indexes) - rule.Build("singleton-merged-hiddenapi-index", "Singleton merged Hidden API index") - - h.index = hiddenAPISingletonPaths(ctx).index -} - -func (h *hiddenAPIIndexSingleton) MakeVars(ctx android.MakeVarsContext) { - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { - return - } - - ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_INDEX", h.index.String()) -} diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index e5e1c2547..5ea9a5bca 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -50,61 +50,6 @@ func TestHiddenAPISingleton(t *testing.T) { android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } -func TestHiddenAPIIndexSingleton(t *testing.T) { - result := android.GroupFixturePreparers( - hiddenApiFixtureFactory, - PrepareForTestWithJavaSdkLibraryFiles, - FixtureWithLastReleaseApis("bar"), - FixtureConfigureBootJars("platform:foo", "platform:bar"), - ).RunTestWithBp(t, ` - java_library { - name: "foo", - srcs: ["a.java"], - compile_dex: true, - - hiddenapi_additional_annotations: [ - "foo-hiddenapi-annotations", - ], - } - - java_library { - name: "foo-hiddenapi-annotations", - srcs: ["a.java"], - compile_dex: true, - } - - java_import { - name: "foo", - jars: ["a.jar"], - compile_dex: true, - prefer: false, - } - - java_sdk_library { - name: "bar", - srcs: ["a.java"], - compile_dex: true, - } - `) - - hiddenAPIIndex := result.SingletonForTests("hiddenapi_index") - indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index") - CheckHiddenAPIRuleInputs(t, ` -.intermediates/bar/android_common/hiddenapi/index.csv -.intermediates/foo/android_common/hiddenapi/index.csv -`, - indexRule) - - // Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that - // creates the index.csv file. - foo := result.ModuleForTests("foo", "android_common") - indexParams := foo.Output("hiddenapi/index.csv") - CheckHiddenAPIRuleInputs(t, ` -.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar -.intermediates/foo/android_common/javac/foo.jar -`, indexParams) -} - func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) { expectedErrorMessage := "hiddenapi has determined that the source module \"foo\" should be ignored as it has been" + diff --git a/java/java.go b/java/java.go index fa7c96eff..ee4f2eb0b 100644 --- a/java/java.go +++ b/java/java.go @@ -356,7 +356,7 @@ func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext an if javaVersion != "" { return normalizeJavaVersion(ctx, javaVersion) } else if ctx.Device() { - return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion()) + return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx)) } else { return JAVA_VERSION_9 } @@ -463,6 +463,9 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { // would the <x> library if <x> was configured as a boot jar. j.initHiddenAPI(ctx, j.ConfigurationName()) + j.sdkVersion = j.SdkVersion(ctx) + j.minSdkVersion = j.MinSdkVersion(ctx) + apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { j.hideApexVariantFromMake = true @@ -1130,33 +1133,28 @@ type Import struct { exportAidlIncludeDirs android.Paths hideApexVariantFromMake bool -} -func (j *Import) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(j.properties.Sdk_version)) + sdkVersion android.SdkSpec + minSdkVersion android.SdkSpec } -func (j *Import) makeSdkVersion() string { - return j.SdkVersion().Raw +func (j *Import) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(j.properties.Sdk_version)) } func (j *Import) SystemModules() string { return "none" } -func (j *Import) MinSdkVersion() android.SdkSpec { +func (j *Import) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { if j.properties.Min_sdk_version != nil { - return android.SdkSpecFrom(*j.properties.Min_sdk_version) + return android.SdkSpecFrom(ctx, *j.properties.Min_sdk_version) } - return j.SdkVersion() + return j.SdkVersion(ctx) } -func (j *Import) TargetSdkVersion() android.SdkSpec { - return j.SdkVersion() -} - -func (j *Import) MinSdkVersionString() string { - return j.MinSdkVersion().ApiLevel.String() +func (j *Import) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return j.SdkVersion(ctx) } func (j *Import) Prebuilt() *android.Prebuilt { @@ -1192,6 +1190,9 @@ func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { } func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { + j.sdkVersion = j.SdkVersion(ctx) + j.minSdkVersion = j.MinSdkVersion(ctx) + // Initialize the hiddenapi structure. j.initHiddenAPI(ctx, j.BaseModuleName()) @@ -1230,7 +1231,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } else if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: - flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...) + flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...) } } @@ -1291,7 +1292,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex var dexOutputFile android.OutputPath - dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(ctx), outputFile, jarName) if ctx.Failed() { return } @@ -1359,7 +1360,7 @@ func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu // Implements android.ApexModule func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - sdkSpec := j.MinSdkVersion() + sdkSpec := j.MinSdkVersion(ctx) if !sdkSpec.Specified() { return fmt.Errorf("min_sdk_version is not specified") } diff --git a/java/java_test.go b/java/java_test.go index fdf757902..052345871 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1261,6 +1261,14 @@ func TestJavaLintUsesCorrectBpConfig(t *testing.T) { if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") { t.Error("did not use the correct file for baseline") } + + if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") { + t.Error("should check NewApi errors") + } + + if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") { + t.Error("should combine NewApi errors with SomeCheck errors") + } } func TestGeneratedSources(t *testing.T) { diff --git a/java/lint.go b/java/lint.go index 30843dc93..aa308e669 100644 --- a/java/lint.go +++ b/java/lint.go @@ -57,24 +57,25 @@ type LintProperties struct { } type linter struct { - name string - manifest android.Path - mergedManifest android.Path - srcs android.Paths - srcJars android.Paths - resources android.Paths - classpath android.Paths - classes android.Path - extraLintCheckJars android.Paths - test bool - library bool - minSdkVersion string - targetSdkVersion string - compileSdkVersion string - javaLanguageLevel string - kotlinLanguageLevel string - outputs lintOutputs - properties LintProperties + name string + manifest android.Path + mergedManifest android.Path + srcs android.Paths + srcJars android.Paths + resources android.Paths + classpath android.Paths + classes android.Path + extraLintCheckJars android.Paths + test bool + library bool + minSdkVersion string + targetSdkVersion string + compileSdkVersion string + javaLanguageLevel string + kotlinLanguageLevel string + outputs lintOutputs + properties LintProperties + extraMainlineLintErrors []string reports android.Paths @@ -246,6 +247,7 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru cmd.FlagWithInput("@", android.PathForSource(ctx, "build/soong/java/lint_defaults.txt")) + cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors) cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks) cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks) cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks) @@ -282,6 +284,10 @@ func (l *linter) lint(ctx android.ModuleContext) { return } + if l.minSdkVersion != l.compileSdkVersion { + l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, "NewApi") + } + extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag) for _, extraLintCheckModule := range extraLintCheckModules { if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) { diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index d98ce6719..994f1beab 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -208,7 +208,30 @@ func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex st // error, unless missing dependencies are allowed. The simplest way to handle that is to add a // dependency that will not be satisfied and the default behavior will handle it. if !addedDep { - ctx.AddFarVariationDependencies(variations, tag, name) + // Add dependency on the unprefixed (i.e. source or renamed prebuilt) module which we know does + // not exist. The resulting error message will contain useful information about the available + // variants. + reportMissingVariationDependency(ctx, variations, name) + + // Add dependency on the missing prefixed prebuilt variant too if a module with that name exists + // so that information about its available variants will be reported too. + if ctx.OtherModuleExists(prebuiltName) { + reportMissingVariationDependency(ctx, variations, prebuiltName) + } + } +} + +// reportMissingVariationDependency intentionally adds a dependency on a missing variation in order +// to generate an appropriate error message with information about the available variations. +func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) { + modules := ctx.AddFarVariationDependencies(variations, nil, name) + if len(modules) != 1 { + panic(fmt.Errorf("Internal Error: expected one module, found %d", len(modules))) + return + } + if modules[0] != nil { + panic(fmt.Errorf("Internal Error: expected module to be missing but was found: %q", modules[0])) + return } } @@ -280,20 +303,78 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. return } - moduleSpecificFlagsPaths := android.Paths{} + hiddenAPISupportingModules := []hiddenAPISupportingModule{} for _, module := range modules { - if h, ok := module.(hiddenAPIIntf); ok { - if csv := h.flagsCSV(); csv != nil { - moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, csv) + if h, ok := module.(hiddenAPISupportingModule); ok { + if h.bootDexJar() == nil { + ctx.ModuleErrorf("module %s does not provide a bootDexJar file", module) + } + if h.flagsCSV() == nil { + ctx.ModuleErrorf("module %s does not provide a flagsCSV file", module) + } + if h.indexCSV() == nil { + ctx.ModuleErrorf("module %s does not provide an indexCSV file", module) + } + if h.metadataCSV() == nil { + ctx.ModuleErrorf("module %s does not provide a metadataCSV file", module) } + + if ctx.Failed() { + continue + } + + hiddenAPISupportingModules = append(hiddenAPISupportingModules, h) } else { - ctx.ModuleErrorf("module %s of type %s does not implement hiddenAPIIntf", module, ctx.OtherModuleType(module)) + ctx.ModuleErrorf("module %s of type %s does not support hidden API processing", module, ctx.OtherModuleType(module)) } } + moduleSpecificFlagsPaths := android.Paths{} + for _, module := range hiddenAPISupportingModules { + moduleSpecificFlagsPaths = append(moduleSpecificFlagsPaths, module.flagsCSV()) + } + augmentationInfo := b.properties.Hidden_api.hiddenAPIAugmentationInfo(ctx) outputPath := hiddenAPISingletonPaths(ctx).flags baseFlagsPath := hiddenAPISingletonPaths(ctx).stubFlags ruleToGenerateHiddenApiFlags(ctx, outputPath, baseFlagsPath, moduleSpecificFlagsPaths, augmentationInfo) + + b.generateHiddenAPIIndexRules(ctx, hiddenAPISupportingModules) + b.generatedHiddenAPIMetadataRules(ctx, hiddenAPISupportingModules) +} + +func (b *platformBootclasspathModule) generateHiddenAPIIndexRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) { + indexes := android.Paths{} + for _, module := range modules { + indexes = append(indexes, module.indexCSV()) + } + + rule := android.NewRuleBuilder(pctx, ctx) + rule.Command(). + BuiltTool("merge_csv"). + Flag("--key_field signature"). + FlagWithArg("--header=", "signature,file,startline,startcol,endline,endcol,properties"). + FlagWithOutput("--output=", hiddenAPISingletonPaths(ctx).index). + Inputs(indexes) + rule.Build("platform-bootclasspath-monolithic-hiddenapi-index", "monolithic hidden API index") +} + +func (b *platformBootclasspathModule) generatedHiddenAPIMetadataRules(ctx android.ModuleContext, modules []hiddenAPISupportingModule) { + metadataCSVFiles := android.Paths{} + for _, module := range modules { + metadataCSVFiles = append(metadataCSVFiles, module.metadataCSV()) + } + + rule := android.NewRuleBuilder(pctx, ctx) + + outputPath := hiddenAPISingletonPaths(ctx).metadata + + rule.Command(). + BuiltTool("merge_csv"). + Flag("--key_field signature"). + FlagWithOutput("--output=", outputPath). + Inputs(metadataCSVFiles) + + rule.Build("platform-bootclasspath-monolithic-hiddenapi-metadata", "monolithic hidden API metadata") } diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go index c740911f1..417c6bf74 100644 --- a/java/platform_bootclasspath_test.go +++ b/java/platform_bootclasspath_test.go @@ -172,3 +172,62 @@ func TestPlatformBootclasspath_Dist(t *testing.T) { android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0]) android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[1])) } + +func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) { + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("bar"), + FixtureConfigureBootJars("platform:foo", "platform:bar"), + ).RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + + hiddenapi_additional_annotations: [ + "foo-hiddenapi-annotations", + ], + } + + java_library { + name: "foo-hiddenapi-annotations", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: false, + } + + java_sdk_library { + name: "bar", + srcs: ["a.java"], + compile_dex: true, + } + + platform_bootclasspath { + name: "myplatform-bootclasspath", + } + `) + + platformBootclasspath := result.ModuleForTests("myplatform-bootclasspath", "android_common") + indexRule := platformBootclasspath.Rule("platform-bootclasspath-monolithic-hiddenapi-index") + CheckHiddenAPIRuleInputs(t, ` +.intermediates/bar/android_common/hiddenapi/index.csv +.intermediates/foo/android_common/hiddenapi/index.csv +`, + indexRule) + + // Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that + // creates the index.csv file. + foo := result.ModuleForTests("foo", "android_common") + indexParams := foo.Output("hiddenapi/index.csv") + CheckHiddenAPIRuleInputs(t, ` +.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar +.intermediates/foo/android_common/javac/foo.jar +`, indexParams) +} diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index 8a442b5ff..c33e6c229 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -253,14 +253,8 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { files := getPrebuiltFilesInSubdir(mctx, nextApiDir, "api/*incompatibilities.txt") for _, f := range files { localPath := strings.TrimPrefix(f, mydir) - module, _, scope := parseApiFilePath(mctx, localPath) - - // Figure out which module is referenced by this file. Special case for "android". - referencedModule := strings.TrimSuffix(module, "incompatibilities") - referencedModule = strings.TrimSuffix(referencedModule, "-") - if referencedModule == "" { - referencedModule = "android" - } + filename, _, scope := parseApiFilePath(mctx, localPath) + referencedModule := strings.TrimSuffix(filename, "-incompatibilities") createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), localPath) diff --git a/java/rro.go b/java/rro.go index 4ae0014db..2e58c042f 100644 --- a/java/rro.go +++ b/java/rro.go @@ -141,23 +141,23 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile) } -func (r *RuntimeResourceOverlay) SdkVersion() android.SdkSpec { - return android.SdkSpecFrom(String(r.properties.Sdk_version)) +func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return android.SdkSpecFrom(ctx, String(r.properties.Sdk_version)) } func (r *RuntimeResourceOverlay) SystemModules() string { return "" } -func (r *RuntimeResourceOverlay) MinSdkVersion() android.SdkSpec { +func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { if r.properties.Min_sdk_version != nil { - return android.SdkSpecFrom(*r.properties.Min_sdk_version) + return android.SdkSpecFrom(ctx, *r.properties.Min_sdk_version) } - return r.SdkVersion() + return r.SdkVersion(ctx) } -func (r *RuntimeResourceOverlay) TargetSdkVersion() android.SdkSpec { - return r.SdkVersion() +func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { + return r.SdkVersion(ctx) } func (r *RuntimeResourceOverlay) Certificate() Certificate { diff --git a/java/sdk.go b/java/sdk.go index f324b7661..d6e20a78f 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -61,7 +61,7 @@ func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpe } func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep { - sdkVersion := sdkContext.SdkVersion() + sdkVersion := sdkContext.SdkVersion(ctx) if !sdkVersion.Valid() { ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.Raw) return sdkDep{} diff --git a/java/sdk_library.go b/java/sdk_library.go index 96135c3d4..e5ee39705 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1512,7 +1512,7 @@ func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion andr // force override sdk_version to module_current so that the closest possible API // surface could be found in selectHeaderJarsForSdkVersion if module.defaultsToStubs() && !sdkVersion.Specified() { - sdkVersion = android.SdkSpecFrom("module_current") + sdkVersion = android.SdkSpecFrom(ctx, "module_current") } // Only provide access to the implementation library if it is actually built. diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go index da80a4715..241cac691 100644 --- a/linkerconfig/linkerconfig.go +++ b/linkerconfig/linkerconfig.go @@ -17,6 +17,7 @@ package linkerconfig import ( "android/soong/android" "android/soong/etc" + "fmt" "github.com/google/blueprint/proptools" ) @@ -68,6 +69,17 @@ func (l *linkerConfig) OutputFile() android.OutputPath { return l.outputFilePath } +var _ android.OutputFileProducer = (*linkerConfig)(nil) + +func (l *linkerConfig) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "": + return android.Paths{l.outputFilePath}, nil + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } +} + func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { inputFile := android.PathForModuleSrc(ctx, android.String(l.properties.Src)) l.outputFilePath = android.PathForModuleOut(ctx, "linker.config.pb").OutputPath @@ -81,9 +93,10 @@ func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { linkerConfigRule.Build("conv_linker_config", "Generate linker config protobuf "+l.outputFilePath.String()) - if proptools.BoolDefault(l.properties.Installable, true) { - ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath) + if !proptools.BoolDefault(l.properties.Installable, true) { + l.SkipInstall() } + ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath) } // linker_config generates protobuf file from json file. This protobuf file will be used from diff --git a/rust/Android.bp b/rust/Android.bp index a29c474b1..a6c4e0787 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -14,6 +14,7 @@ bootstrap_go_package { ], srcs: [ "androidmk.go", + "benchmark.go", "binary.go", "bindgen.go", "builder.go", @@ -35,6 +36,7 @@ bootstrap_go_package { "testing.go", ], testSrcs: [ + "benchmark_test.go", "binary_test.go", "bindgen_test.go", "builder_test.go", diff --git a/rust/androidmk.go b/rust/androidmk.go index dea32a34d..5f89d73c7 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -60,6 +60,10 @@ func (mod *Module) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...) entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...) entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType) + if mod.UseVndk() { + entries.SetBool("LOCAL_USE_VNDK", true) + } + }, }, } @@ -75,6 +79,7 @@ func (mod *Module) AndroidMkEntries() []android.AndroidMkEntries { mod.SubAndroidMk(&ret, mod.sanitize) } + ret.SubName += mod.Properties.RustSubName ret.SubName += mod.Properties.SubName return []android.AndroidMkEntries{ret} @@ -107,6 +112,20 @@ func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidM cc.AndroidMkWriteTestData(test.data, ret) } +func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { + benchmark.binaryDecorator.AndroidMk(ctx, ret) + ret.Class = "NATIVE_TESTS" + ret.ExtraEntries = append(ret.ExtraEntries, + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...) + if benchmark.testConfig != nil { + entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String()) + } + entries.SetBool("LOCAL_NATIVE_BENCHMARK", true) + entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(benchmark.Properties.Auto_gen_config, true)) + }) +} + func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { ctx.SubAndroidMk(ret, library.baseCompiler) diff --git a/rust/benchmark.go b/rust/benchmark.go new file mode 100644 index 000000000..b89f5cd9b --- /dev/null +++ b/rust/benchmark.go @@ -0,0 +1,129 @@ +// Copyright 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rust + +import ( + "android/soong/android" + "android/soong/tradefed" +) + +type BenchmarkProperties struct { + // Disables the creation of a test-specific directory when used with + // relative_install_path. Useful if several tests need to be in the same + // directory, but test_per_src doesn't work. + No_named_install_directory *bool + + // the name of the test configuration (for example "AndroidBenchmark.xml") that should be + // installed with the module. + Test_config *string `android:"path,arch_variant"` + + // the name of the test configuration template (for example "AndroidBenchmarkTemplate.xml") that + // should be installed with the module. + Test_config_template *string `android:"path,arch_variant"` + + // list of compatibility suites (for example "cts", "vts") that the module should be + // installed into. + Test_suites []string `android:"arch_variant"` + + // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml + // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true + // explicitly. + Auto_gen_config *bool +} + +type benchmarkDecorator struct { + *binaryDecorator + Properties BenchmarkProperties + testConfig android.Path +} + +func NewRustBenchmark(hod android.HostOrDeviceSupported) (*Module, *benchmarkDecorator) { + // Build both 32 and 64 targets for device benchmarks. + // Cannot build both for host benchmarks yet if the benchmark depends on + // something like proc-macro2 that cannot be built for both. + multilib := android.MultilibBoth + if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported { + multilib = android.MultilibFirst + } + module := newModule(hod, multilib) + + benchmark := &benchmarkDecorator{ + binaryDecorator: &binaryDecorator{ + baseCompiler: NewBaseCompiler("nativebench", "nativebench64", InstallInData), + }, + } + + module.compiler = benchmark + module.AddProperties(&benchmark.Properties) + return module, benchmark +} + +func init() { + android.RegisterModuleType("rust_benchmark", RustBenchmarkFactory) + android.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory) +} + +func RustBenchmarkFactory() android.Module { + module, _ := NewRustBenchmark(android.HostAndDeviceSupported) + return module.Init() +} + +func RustBenchmarkHostFactory() android.Module { + module, _ := NewRustBenchmark(android.HostSupported) + return module.Init() +} + +func (benchmark *benchmarkDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep { + return rlibAutoDep +} + +func (benchmark *benchmarkDecorator) stdLinkage(ctx *depsContext) RustLinkage { + return RlibLinkage +} + +func (benchmark *benchmarkDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { + flags = benchmark.binaryDecorator.compilerFlags(ctx, flags) + return flags +} + +func (benchmark *benchmarkDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { + deps = benchmark.binaryDecorator.compilerDeps(ctx, deps) + + deps.Rustlibs = append(deps.Rustlibs, "libcriterion") + + return deps +} + +func (benchmark *benchmarkDecorator) compilerProps() []interface{} { + return append(benchmark.binaryDecorator.compilerProps(), &benchmark.Properties) +} + +func (benchmark *benchmarkDecorator) install(ctx ModuleContext) { + benchmark.testConfig = tradefed.AutoGenRustBenchmarkConfig(ctx, + benchmark.Properties.Test_config, + benchmark.Properties.Test_config_template, + benchmark.Properties.Test_suites, + nil, + benchmark.Properties.Auto_gen_config) + + // default relative install path is module name + if !Bool(benchmark.Properties.No_named_install_directory) { + benchmark.baseCompiler.relative = ctx.ModuleName() + } else if String(benchmark.baseCompiler.Properties.Relative_install_path) == "" { + ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set") + } + + benchmark.binaryDecorator.install(ctx) +} diff --git a/rust/benchmark_test.go b/rust/benchmark_test.go new file mode 100644 index 000000000..734dda71d --- /dev/null +++ b/rust/benchmark_test.go @@ -0,0 +1,54 @@ +// Copyright 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rust + +import ( + "strings" + "testing" + + "android/soong/android" +) + +func TestRustBenchmark(t *testing.T) { + ctx := testRust(t, ` + rust_benchmark_host { + name: "my_bench", + srcs: ["foo.rs"], + }`) + + testingModule := ctx.ModuleForTests("my_bench", "linux_glibc_x86_64") + expectedOut := "my_bench/linux_glibc_x86_64/my_bench" + outPath := testingModule.Output("my_bench").Output.String() + if !strings.Contains(outPath, expectedOut) { + t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut) + } +} + +func TestRustBenchmarkLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_benchmark { + name: "my_bench", + srcs: ["foo.rs"], + }`) + + testingModule := ctx.ModuleForTests("my_bench", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libcriterion.rlib-std", testingModule.Properties.AndroidMkRlibs) { + t.Errorf("rlib-std variant for libcriterion not detected as a rustlib-defined rlib dependency for device rust_benchmark module") + } + if !android.InList("libstd", testingModule.Properties.AndroidMkRlibs) { + t.Errorf("Device rust_benchmark module 'my_bench' does not link libstd as an rlib") + } +} diff --git a/rust/compiler.go b/rust/compiler.go index aaa192402..bc034d7cc 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -303,7 +303,6 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { if ctx.Target().Os == android.BuildOs { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } - deps.Stdlibs = append(deps.Stdlibs, stdlib) } } @@ -344,6 +343,10 @@ func (compiler *baseCompiler) installDir(ctx ModuleContext) android.InstallPath if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) { dir = filepath.Join(dir, ctx.Arch().ArchType.String()) } + + if compiler.location == InstallInData && ctx.RustModule().UseVndk() { + dir = filepath.Join(dir, "vendor") + } return android.PathForModuleInstall(ctx, dir, compiler.subDir, compiler.relativeInstallPath(), compiler.relative) } diff --git a/rust/fuzz.go b/rust/fuzz.go index 6b0a943f2..d69997114 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -73,9 +73,6 @@ func (fuzzer *fuzzDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { if libFuzzerRuntimeLibrary := config.LibFuzzerRuntimeLibrary(ctx.toolchain()); libFuzzerRuntimeLibrary != "" { deps.StaticLibs = append(deps.StaticLibs, libFuzzerRuntimeLibrary) } - if libclangRuntimeLibrary := config.LibclangRuntimeLibrary(ctx.toolchain(), "asan"); libclangRuntimeLibrary != "" { - deps.SharedLibs = append(deps.SharedLibs, libclangRuntimeLibrary) - } deps.SharedLibs = append(deps.SharedLibs, "libc++") deps.Rlibs = append(deps.Rlibs, "liblibfuzzer_sys") diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go index f93ccc79f..2524f9176 100644 --- a/rust/fuzz_test.go +++ b/rust/fuzz_test.go @@ -37,9 +37,6 @@ func TestRustFuzz(t *testing.T) { // Check that appropriate dependencies are added and that the rustlib linkage is correct. fuzz_libtest_mod := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module) - if !android.InList("libclang_rt.asan-aarch64-android", fuzz_libtest_mod.Properties.AndroidMkSharedLibs) { - t.Errorf("libclang_rt.asan-aarch64-android shared library dependency missing for rust_fuzz module.") - } if !android.InList("liblibfuzzer_sys.rlib-std", fuzz_libtest_mod.Properties.AndroidMkRlibs) { t.Errorf("liblibfuzzer_sys rlib library dependency missing for rust_fuzz module. %#v", fuzz_libtest_mod.Properties.AndroidMkRlibs) } @@ -49,18 +46,18 @@ func TestRustFuzz(t *testing.T) { // Check that compiler flags are set appropriately . fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Output("fuzz_libtest") - if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=address") || + if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=hwaddress") || !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov'") || !strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") { - t.Errorf("rust_fuzz module does not contain the expected flags (sancov, cfg fuzzing, address sanitizer).") + t.Errorf("rust_fuzz module does not contain the expected flags (sancov, cfg fuzzing, hwaddress sanitizer).") } // Check that dependencies have 'fuzzer' variants produced for them as well. libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib") - if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=address") || + if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=hwaddress") || !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov'") || !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") { - t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov, cfg fuzzing, address sanitizer).") + t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov, cfg fuzzing, hwaddress sanitizer).") } } diff --git a/rust/image.go b/rust/image.go index 628aca3e4..900842ec8 100644 --- a/rust/image.go +++ b/rust/image.go @@ -23,6 +23,68 @@ import ( var _ android.ImageInterface = (*Module)(nil) +var _ cc.ImageMutatableModule = (*Module)(nil) + +func (mod *Module) VendorAvailable() bool { + return Bool(mod.VendorProperties.Vendor_available) +} + +func (mod *Module) OdmAvailable() bool { + return Bool(mod.VendorProperties.Odm_available) +} + +func (mod *Module) ProductAvailable() bool { + return false +} + +func (mod *Module) RamdiskAvailable() bool { + return false +} + +func (mod *Module) VendorRamdiskAvailable() bool { + return Bool(mod.Properties.Vendor_ramdisk_available) +} + +func (mod *Module) AndroidModuleBase() *android.ModuleBase { + return &mod.ModuleBase +} + +func (mod *Module) RecoveryAvailable() bool { + return false +} + +func (mod *Module) ExtraVariants() []string { + return mod.Properties.ExtraVariants +} + +func (mod *Module) AppendExtraVariant(extraVariant string) { + mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, extraVariant) +} + +func (mod *Module) SetRamdiskVariantNeeded(b bool) { + if b { + panic("Setting ramdisk variant needed for Rust module is unsupported: " + mod.BaseModuleName()) + } +} + +func (mod *Module) SetVendorRamdiskVariantNeeded(b bool) { + mod.Properties.VendorRamdiskVariantNeeded = b +} + +func (mod *Module) SetRecoveryVariantNeeded(b bool) { + if b { + panic("Setting recovery variant needed for Rust module is unsupported: " + mod.BaseModuleName()) + } +} + +func (mod *Module) SetCoreVariantNeeded(b bool) { + mod.Properties.CoreVariantNeeded = b +} + +func (mod *Module) SnapshotVersion(mctx android.BaseModuleContext) string { + panic("Rust modules do not support snapshotting: " + mod.BaseModuleName()) +} + func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return mod.Properties.VendorRamdiskVariantNeeded } @@ -35,6 +97,10 @@ func (mod *Module) RamdiskVariantNeeded(android.BaseModuleContext) bool { return mod.InRamdisk() } +func (mod *Module) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return false +} + func (mod *Module) RecoveryVariantNeeded(android.BaseModuleContext) bool { return mod.InRecovery() } @@ -43,6 +109,29 @@ func (mod *Module) ExtraImageVariations(android.BaseModuleContext) []string { return mod.Properties.ExtraVariants } +func (mod *Module) IsSnapshotPrebuilt() bool { + // Rust does not support prebuilts in its snapshots + return false +} + +func (ctx *moduleContext) SocSpecific() bool { + // Additionally check if this module is inVendor() that means it is a "vendor" variant of a + // module. As well as SoC specific modules, vendor variants must be installed to /vendor + // unless they have "odm_available: true". + return ctx.ModuleContext.SocSpecific() || (ctx.RustModule().InVendor() && !ctx.RustModule().VendorVariantToOdm()) +} + +func (ctx *moduleContext) DeviceSpecific() bool { + // Some vendor variants want to be installed to /odm by setting "odm_available: true". + return ctx.ModuleContext.DeviceSpecific() || (ctx.RustModule().InVendor() && ctx.RustModule().VendorVariantToOdm()) +} + +// Returns true when this module creates a vendor variant and wants to install the vendor variant +// to the odm partition. +func (c *Module) VendorVariantToOdm() bool { + return Bool(c.VendorProperties.Odm_available) +} + func (ctx *moduleContext) ProductSpecific() bool { return false } @@ -84,10 +173,15 @@ func (mod *Module) HasNonSystemVariants() bool { return mod.HasVendorVariant() || mod.HasProductVariant() } -func (c *Module) InProduct() bool { +func (mod *Module) InProduct() bool { return false } +// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor +func (mod *Module) InVendor() bool { + return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix +} + func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) { m := module.(*Module) if variant == android.VendorRamdiskVariation { @@ -107,9 +201,6 @@ func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant stri } func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { - vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific() - platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() - // Rust does not support installing to the product image yet. if Bool(mod.VendorProperties.Product_available) { mctx.PropertyErrorf("product_available", @@ -121,60 +212,19 @@ func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { mctx.PropertyErrorf("double_loadable", "Rust modules do not yet support double loading") } - - coreVariantNeeded := true - vendorRamdiskVariantNeeded := false - - var vendorVariants []string - - if mod.HasVendorVariant() { - prop := "vendor_available" - if Bool(mod.VendorProperties.Odm_available) { - prop = "odm_available" - } - - if vendorSpecific { - mctx.PropertyErrorf(prop, - "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific: true`") - } - - if lib, ok := mod.compiler.(libraryInterface); ok { - // Explicitly disallow rust_ffi variants which produce shared libraries from setting vendor_available. - // Vendor variants do not produce an error for dylibs, rlibs with dylib-std linkage are disabled in the respective library - // mutators until support is added. - // - // We can't check shared() here because image mutator is called before the library mutator, so we need to - // check buildShared() - if lib.buildShared() { - mctx.PropertyErrorf(prop, "cannot be set for rust_ffi or rust_ffi_shared modules.") - } else { - vendorVariants = append(vendorVariants, platformVndkVersion) - } - } - } - if Bool(mod.Properties.Vendor_ramdisk_available) { if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && lib.buildShared()) { mctx.PropertyErrorf("vendor_ramdisk_available", "cannot be set for rust_ffi or rust_ffi_shared modules.") - } else { - vendorRamdiskVariantNeeded = true } } - if vendorSpecific { - if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && (lib.buildShared() || lib.buildDylib() || lib.buildRlib())) { - mctx.ModuleErrorf("Rust vendor specific modules are currently only supported for rust_ffi_static modules.") - } else { - coreVariantNeeded = false - vendorVariants = append(vendorVariants, platformVndkVersion) - } - } + cc.MutateImage(mctx, mod) - mod.Properties.CoreVariantNeeded = coreVariantNeeded - mod.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded + if !mod.Properties.CoreVariantNeeded || mod.HasNonSystemVariants() { - for _, variant := range android.FirstUniqueStrings(vendorVariants) { - mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, cc.VendorVariationPrefix+variant) + if _, ok := mod.compiler.(*prebuiltLibraryDecorator); ok { + // Rust does not support prebuilt libraries on non-System images. + mctx.ModuleErrorf("Rust prebuilt modules not supported for non-system images.") + } } - } diff --git a/rust/image_test.go b/rust/image_test.go index 7677cce3b..95e788f88 100644 --- a/rust/image_test.go +++ b/rust/image_test.go @@ -40,8 +40,8 @@ func TestVendorLinkage(t *testing.T) { vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.29_arm64_armv8-a").Module().(*cc.Module) - if !android.InList("libfoo_vendor", vendorBinary.Properties.AndroidMkStaticLibs) { - t.Errorf("vendorBinary should have a dependency on libfoo_vendor") + if !android.InList("libfoo_vendor.vendor", vendorBinary.Properties.AndroidMkStaticLibs) { + t.Errorf("vendorBinary should have a dependency on libfoo_vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs) } } @@ -87,47 +87,19 @@ func TestVendorRamdiskLinkage(t *testing.T) { } } -// Test that shared libraries cannot be made vendor available until proper support is added. +// Test that prebuilt libraries cannot be made vendor available. func TestForbiddenVendorLinkage(t *testing.T) { - testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", ` - rust_ffi_shared { - name: "libfoo_vendor", - crate_name: "foo", - srcs: ["foo.rs"], - vendor_available: true, - } - `) - testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", ` - rust_ffi_shared { - name: "libfoo_vendor", - crate_name: "foo", - srcs: ["foo.rs"], - vendor_ramdisk_available: true, - } - `) - testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", ` - rust_ffi { - name: "libfoo_vendor", - crate_name: "foo", - srcs: ["foo.rs"], - vendor: true, - } - `) - testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", ` - rust_library { - name: "libfoo_vendor", - crate_name: "foo", - srcs: ["foo.rs"], + testRustVndkError(t, "Rust prebuilt modules not supported for non-system images.", ` + rust_prebuilt_library { + name: "librust_prebuilt", + crate_name: "rust_prebuilt", + rlib: { + srcs: ["libtest.rlib"], + }, + dylib: { + srcs: ["libtest.so"], + }, vendor: true, } - `) - testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", ` - rust_binary { - name: "foo_vendor", - crate_name: "foo", - srcs: ["foo.rs"], - vendor: true, - } - `) - + `) } diff --git a/rust/library.go b/rust/library.go index 71fe1f538..ae130a353 100644 --- a/rust/library.go +++ b/rust/library.go @@ -596,9 +596,9 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { v.(*Module).compiler.(libraryInterface).setRlib() case dylibVariation: v.(*Module).compiler.(libraryInterface).setDylib() - if v.(*Module).ModuleBase.ImageVariation().Variation != android.CoreVariation { + if v.(*Module).ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation { // TODO(b/165791368) - // Disable dylib non-core variations until we support these. + // Disable dylib Vendor Ramdisk variations until we support these. v.(*Module).Disable() } case "source": @@ -637,14 +637,14 @@ func LibstdMutator(mctx android.BottomUpMutatorContext) { dylib := modules[1].(*Module) rlib.compiler.(libraryInterface).setRlibStd() dylib.compiler.(libraryInterface).setDylibStd() - if dylib.ModuleBase.ImageVariation().Variation != android.CoreVariation { + if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation { // TODO(b/165791368) - // Disable rlibs that link against dylib-std on non-core variations until non-core dylib + // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib // variants are properly supported. dylib.Disable() } - rlib.Properties.SubName += RlibStdlibSuffix - dylib.Properties.SubName += DylibStdlibSuffix + rlib.Properties.RustSubName += RlibStdlibSuffix + dylib.Properties.RustSubName += DylibStdlibSuffix } } } diff --git a/rust/rust.go b/rust/rust.go index 34e197a07..d2de1bcae 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -73,6 +73,11 @@ type BaseProperties struct { VndkVersion string `blueprint:"mutated"` SubName string `blueprint:"mutated"` + // SubName is used by CC for tracking image variants / SDK versions. RustSubName is used for Rust-specific + // subnaming which shouldn't be visible to CC modules (such as the rlib stdlinkage subname). This should be + // appended before SubName. + RustSubName string `blueprint:"mutated"` + // Set by imageMutator CoreVariantNeeded bool `blueprint:"mutated"` VendorRamdiskVariantNeeded bool `blueprint:"mutated"` @@ -131,11 +136,6 @@ func (mod *Module) SetPreventInstall() { mod.Properties.PreventInstall = true } -// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor -func (mod *Module) InVendor() bool { - return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix -} - func (mod *Module) SetHideFromMake() { mod.Properties.HideFromMake = true } @@ -231,7 +231,11 @@ func (mod *Module) UseVndk() bool { } func (mod *Module) MustUseVendorVariant() bool { - return false + return true +} + +func (mod *Module) SubName() string { + return mod.Properties.SubName } func (mod *Module) IsVndk() bool { @@ -255,6 +259,22 @@ func (c *Module) IsLlndkPublic() bool { return false } +func (m *Module) IsLlndkHeaders() bool { + return false +} + +func (m *Module) IsLlndkLibrary() bool { + return false +} + +func (mod *Module) KernelHeadersDecorator() bool { + return false +} + +func (m *Module) HasLlndkStubs() bool { + return false +} + func (mod *Module) SdkVersion() string { return "" } @@ -434,6 +454,7 @@ func DefaultsFactory(props ...interface{}) android.Module { module.AddProperties( &BaseProperties{}, &cc.VendorProperties{}, + &BenchmarkProperties{}, &BindgenProperties{}, &BaseCompilerProperties{}, &BinaryCompilerProperties{}, @@ -842,8 +863,10 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { ctx.VisitDirectDeps(func(dep android.Module) { depName := ctx.OtherModuleName(dep) depTag := ctx.OtherModuleDependencyTag(dep) + if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() { //Handle Rust Modules + makeLibName := cc.MakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName) switch depTag { case dylibDepTag: @@ -853,19 +876,19 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } directDylibDeps = append(directDylibDeps, rustDep) - mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName) + mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName) case rlibDepTag: rlib, ok := rustDep.compiler.(libraryInterface) if !ok || !rlib.rlib() { - ctx.ModuleErrorf("mod %q not an rlib library", depName+rustDep.Properties.SubName) + ctx.ModuleErrorf("mod %q not an rlib library", makeLibName) return } directRlibDeps = append(directRlibDeps, rustDep) - mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName+rustDep.Properties.SubName) + mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName) case procMacroDepTag: directProcMacroDeps = append(directProcMacroDeps, rustDep) - mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName) + mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName) case android.SourceDepTag: // Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct // OS/Arch variant is used. @@ -909,6 +932,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } else if ccDep, ok := dep.(cc.LinkableInterface); ok { //Handle C dependencies + makeLibName := cc.MakeLibName(ctx, mod, ccDep, depName) if _, ok := ccDep.(*Module); !ok { if ccDep.Module().Target().Os != ctx.Os() { ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName) @@ -950,7 +974,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...) depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...) directStaticLibDeps = append(directStaticLibDeps, ccDep) - mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName) + mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, makeLibName) case cc.IsSharedDepTag(depTag): depPaths.linkDirs = append(depPaths.linkDirs, linkPath) depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) @@ -960,7 +984,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...) depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...) directSharedLibDeps = append(directSharedLibDeps, ccDep) - mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName) + mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, makeLibName) exportDep = true case cc.IsHeaderDepTag(depTag): exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo) diff --git a/rust/rust_test.go b/rust/rust_test.go index 890fb262b..47c64a9ad 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -113,6 +113,24 @@ func testRustError(t *testing.T, pattern string, bp string) { RunTestWithBp(t, bp) } +// testRustVndkError is similar to testRustError, but can be used to test VNDK-related errors. +func testRustVndkError(t *testing.T, pattern string, bp string) { + skipTestIfOsNotSupported(t) + android.GroupFixturePreparers( + prepareForRustTest, + rustMockedFiles.AddToFixture(), + android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.DeviceVndkVersion = StringPtr("current") + variables.ProductVndkVersion = StringPtr("current") + variables.Platform_vndk_version = StringPtr("VER") + }, + ), + ). + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)). + RunTestWithBp(t, bp) +} + // testRustCtx is used to build a particular test environment. Unless your // tests requires a specific setup, prefer the wrapping functions: testRust, // testRustCov or testRustError. diff --git a/rust/sanitize.go b/rust/sanitize.go index ae3eff006..0a53f989f 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -46,7 +46,6 @@ var fuzzerFlags = []string{ "-C llvm-args=-sanitizer-coverage-inline-8bit-counters", "-C llvm-args=-sanitizer-coverage-trace-geps", "-C llvm-args=-sanitizer-coverage-prune-blocks=0", - "-Z sanitizer=address", // Sancov breaks with lto // TODO: Remove when https://bugs.llvm.org/show_bug.cgi?id=41734 is resolved and sancov works with LTO @@ -109,6 +108,11 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags, deps PathDeps) ( } if Bool(sanitize.Properties.Sanitize.Fuzzer) { flags.RustFlags = append(flags.RustFlags, fuzzerFlags...) + if ctx.Arch().ArchType == android.Arm64 { + flags.RustFlags = append(flags.RustFlags, hwasanFlags...) + } else { + flags.RustFlags = append(flags.RustFlags, asanFlags...) + } } if Bool(sanitize.Properties.Sanitize.Address) { flags.RustFlags = append(flags.RustFlags, asanFlags...) @@ -133,12 +137,14 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { var depTag blueprint.DependencyTag var deps []string - if Bool(mod.sanitize.Properties.Sanitize.Fuzzer) || Bool(mod.sanitize.Properties.Sanitize.Address) { + if mod.IsSanitizerEnabled(cc.Asan) || + (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType != android.Arm64) { variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"}) depTag = cc.SharedDepTag() deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")} - } else if mod.IsSanitizerEnabled(cc.Hwasan) { + } else if mod.IsSanitizerEnabled(cc.Hwasan) || + (mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64) { // TODO(b/180495975): HWASan for static Rust binaries isn't supported yet. if binary, ok := mod.compiler.(*binaryDecorator); ok { if Bool(binary.Properties.Static_executable) { @@ -285,11 +291,9 @@ func (mod *Module) SetSanitizeDep(b bool) { func (mod *Module) StaticallyLinked() bool { if lib, ok := mod.compiler.(libraryInterface); ok { - if lib.rlib() || lib.static() { - return true - } - } else if Bool(mod.compiler.(*binaryDecorator).Properties.Static_executable) { - return true + return lib.rlib() || lib.static() + } else if binary, ok := mod.compiler.(*binaryDecorator); ok { + return Bool(binary.Properties.Static_executable) } return false } diff --git a/rust/testing.go b/rust/testing.go index 75adcfce9..2dda9c144 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -127,6 +127,7 @@ func GatherRequiredDepsForTest() string { system_shared_libs: [], apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", + vendor_available: true, } cc_library { name: "libprotobuf-cpp-full", @@ -150,7 +151,7 @@ func GatherRequiredDepsForTest() string { host_supported: true, vendor_available: true, vendor_ramdisk_available: true, - native_coverage: false, + native_coverage: false, sysroot: true, apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", @@ -163,7 +164,7 @@ func GatherRequiredDepsForTest() string { host_supported: true, vendor_available: true, vendor_ramdisk_available: true, - native_coverage: false, + native_coverage: false, sysroot: true, apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", @@ -192,11 +193,19 @@ func GatherRequiredDepsForTest() string { srcs:["foo.rs"], host_supported: true, } + rust_library { + name: "libcriterion", + crate_name: "criterion", + srcs:["foo.rs"], + host_supported: true, + } ` return bp } func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { + ctx.RegisterModuleType("rust_benchmark", RustBenchmarkFactory) + ctx.RegisterModuleType("rust_benchmark_host", RustBenchmarkHostFactory) ctx.RegisterModuleType("rust_binary", RustBinaryFactory) ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory) ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory) diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py index 22fe9f671..92f79dae8 100644 --- a/scripts/conv_linker_config.py +++ b/scripts/conv_linker_config.py @@ -78,6 +78,14 @@ def Append(args): with open(args.output, 'wb') as f: f.write(pb.SerializeToString()) +def Merge(args): + pb = linker_config_pb2.LinkerConfig() + for other in args.input: + with open(other, 'rb') as f: + pb.MergeFromString(f.read()) + + with open(args.out, 'wb') as f: + f.write(pb.SerializeToString()) def GetArgParser(): parser = argparse.ArgumentParser() @@ -161,6 +169,22 @@ def GetArgParser(): help='Values of the libraries to append. If there are more than one it should be separated by empty space') append.set_defaults(func=Append) + append = subparsers.add_parser( + 'merge', help='Merge configurations') + append.add_argument( + '-o', + '--out', + required=True, + type=str, + help='Ouptut linker configuration file to write in protobuf.') + append.add_argument( + '-i', + '--input', + nargs='+', + type=str, + help='Linker configuration files to merge.') + append.set_defaults(func=Merge) + return parser diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 662338133..42d5680f1 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -210,6 +210,10 @@ func (s *ShBinary) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) boo return proptools.Bool(s.properties.Vendor_ramdisk_available) || s.ModuleBase.InstallInVendorRamdisk() } +func (s *ShBinary) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return false +} + func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery() } diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh index 5271f8d9e..f1ebca296 100755 --- a/tests/bootstrap_test.sh +++ b/tests/bootstrap_test.sh @@ -114,7 +114,9 @@ EOF rm a/Android.bp run_soong - grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja && fail "Old module in output" + if grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja; then + fail "Old module in output" + fi } function test_add_file_to_glob() { @@ -404,7 +406,9 @@ EOF grep -q "Engage" out/soong/build.ninja || fail "New action not present" - grep -q "Make it so" out/soong/build.ninja && fail "Original action still present" + if grep -q "Make it so" out/soong/build.ninja; then + fail "Original action still present" + fi } function test_null_build_after_docs { @@ -421,6 +425,83 @@ function test_null_build_after_docs { fi } +function test_integrated_bp2build_smoke { + setup + INTEGRATED_BP2BUILD=1 run_soong + if [[ ! -e out/soong/.bootstrap/bp2build_workspace_marker ]]; then + fail "bp2build marker file not created" + fi +} + +function test_integrated_bp2build_add_android_bp { + setup + + mkdir -p a + touch a/a.txt + cat > a/Android.bp <<'EOF' +filegroup { + name: "a", + srcs: ["a.txt"], + bazel_module: { bp2build_available: true }, +} +EOF + + INTEGRATED_BP2BUILD=1 run_soong + if [[ ! -e out/soong/bp2build/a/BUILD ]]; then + fail "a/BUILD not created"; + fi + + mkdir -p b + touch b/b.txt + cat > b/Android.bp <<'EOF' +filegroup { + name: "b", + srcs: ["b.txt"], + bazel_module: { bp2build_available: true }, +} +EOF + + INTEGRATED_BP2BUILD=1 run_soong + if [[ ! -e out/soong/bp2build/b/BUILD ]]; then + fail "b/BUILD not created"; + fi +} + +function test_integrated_bp2build_null_build { + setup + + INTEGRATED_BP2BUILD=1 run_soong + local mtime1=$(stat -c "%y" out/soong/build.ninja) + + INTEGRATED_BP2BUILD=1 run_soong + local mtime2=$(stat -c "%y" out/soong/build.ninja) + + if [[ "$mtime1" != "$mtime2" ]]; then + fail "Output Ninja file changed on null build" + fi +} + +function test_integrated_bp2build_add_to_glob { + setup + + mkdir -p a + touch a/a1.txt + cat > a/Android.bp <<'EOF' +filegroup { + name: "a", + srcs: ["*.txt"], + bazel_module: { bp2build_available: true }, +} +EOF + + INTEGRATED_BP2BUILD=1 run_soong + grep -q a1.txt out/soong/bp2build/a/BUILD || fail "a1.txt not in BUILD file" + + touch a/a2.txt + INTEGRATED_BP2BUILD=1 run_soong + grep -q a2.txt out/soong/bp2build/a/BUILD || fail "a2.txt not in BUILD file" +} + function test_dump_json_module_graph() { setup SOONG_DUMP_JSON_MODULE_GRAPH="$MOCK_TOP/modules.json" run_soong @@ -441,3 +522,6 @@ test_add_file_to_soong_build test_glob_during_bootstrapping test_soong_build_rerun_iff_environment_changes test_dump_json_module_graph +test_integrated_bp2build_smoke +test_integrated_bp2build_null_build +test_integrated_bp2build_add_to_glob diff --git a/tests/lib.sh b/tests/lib.sh index 3c97e141c..1478e3746 100644 --- a/tests/lib.sh +++ b/tests/lib.sh @@ -6,8 +6,39 @@ HARDWIRED_MOCK_TOP= REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)" +if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then + MOCK_TOP="$HARDWIRED_MOCK_TOP" +else + MOCK_TOP=$(mktemp -t -d st.XXXXX) + trap cleanup_mock_top EXIT +fi + +WARMED_UP_MOCK_TOP=$(mktemp -t soong_integration_tests_warmup.XXXXXX.tar.gz) +trap 'rm -f "$WARMED_UP_MOCK_TOP"' EXIT + +function warmup_mock_top { + info "Warming up mock top ..." + info "Mock top warmup archive: $WARMED_UP_MOCK_TOP" + cleanup_mock_top + mkdir -p "$MOCK_TOP" + cd "$MOCK_TOP" + + create_mock_soong + run_soong + tar czf "$WARMED_UP_MOCK_TOP" * +} + +function cleanup_mock_top { + cd / + rm -fr "$MOCK_TOP" +} + +function info { + echo -e "\e[92;1m[TEST HARNESS INFO]\e[0m" $* +} + function fail { - echo ERROR: $1 + echo -e "\e[91;1mFAILED:\e[0m" $* exit 1 } @@ -47,19 +78,7 @@ function symlink_directory() { done } -function setup() { - if [[ ! -z "$HARDWIRED_MOCK_TOP" ]]; then - MOCK_TOP="$HARDWIRED_MOCK_TOP" - rm -fr "$MOCK_TOP" - mkdir -p "$MOCK_TOP" - else - MOCK_TOP=$(mktemp -t -d st.XXXXX) - trap 'echo cd / && echo rm -fr "$MOCK_TOP"' EXIT - fi - - echo "Test case: ${FUNCNAME[1]}, mock top path: $MOCK_TOP" - cd "$MOCK_TOP" - +function create_mock_soong { copy_directory build/blueprint copy_directory build/soong @@ -68,12 +87,27 @@ function setup() { symlink_directory external/golang-protobuf touch "$MOCK_TOP/Android.bp" +} - export ALLOW_MISSING_DEPENDENCIES=true +function setup() { + cleanup_mock_top + mkdir -p "$MOCK_TOP" - mkdir -p out/soong + echo + echo ---------------------------------------------------------------------------- + info "Running test case ${FUNCNAME[1]}" + cd "$MOCK_TOP" + + tar xzf "$WARMED_UP_MOCK_TOP" } function run_soong() { build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests } + +info "Starting Soong integration test suite $(basename $0)" +info "Mock top: $MOCK_TOP" + + +export ALLOW_MISSING_DEPENDENCIES=true +warmup_mock_top diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh index 54f06897c..7dbafea01 100755 --- a/tests/mixed_mode_test.sh +++ b/tests/mixed_mode_test.sh @@ -8,7 +8,7 @@ source "$(dirname "$0")/lib.sh" -function setup_bazel() { +function create_mock_bazel() { copy_directory build/bazel symlink_directory prebuilts/bazel @@ -20,7 +20,7 @@ function setup_bazel() { function test_bazel_smoke { setup - setup_bazel + create_mock_bazel tools/bazel info } diff --git a/tradefed/autogen.go b/tradefed/autogen.go index 27d71e828..3d96c8457 100644 --- a/tradefed/autogen.go +++ b/tradefed/autogen.go @@ -245,6 +245,25 @@ func AutoGenRustTestConfig(ctx android.ModuleContext, testConfigProp *string, return path } +func AutoGenRustBenchmarkConfig(ctx android.ModuleContext, testConfigProp *string, + testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path { + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp) + if autogenPath != nil { + templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) + if templatePath.Valid() { + autogenTemplate(ctx, autogenPath, templatePath.String(), config, "") + } else { + if ctx.Device() { + autogenTemplate(ctx, autogenPath, "${RustDeviceBenchmarkConfigTemplate}", config, "") + } else { + autogenTemplate(ctx, autogenPath, "${RustHostBenchmarkConfigTemplate}", config, "") + } + } + return autogenPath + } + return path +} + func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path { path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp) diff --git a/tradefed/config.go b/tradefed/config.go index f3566a80d..999424cfb 100644 --- a/tradefed/config.go +++ b/tradefed/config.go @@ -34,6 +34,8 @@ func init() { pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml") pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml") pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml") + pctx.SourcePathVariable("RustDeviceBenchmarkConfigTemplate", "build/make/core/rust_device_benchmark_config_template.xml") + pctx.SourcePathVariable("RustHostBenchmarkConfigTemplate", "build/make/core/rust_host_benchmark_config_template.xml") pctx.SourcePathVariable("RobolectricTestConfigTemplate", "build/make/core/robolectric_test_config_template.xml") pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml") diff --git a/tradefed/makevars.go b/tradefed/makevars.go index f9682e448..9b5a20f47 100644 --- a/tradefed/makevars.go +++ b/tradefed/makevars.go @@ -33,6 +33,8 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("PYTHON_BINARY_HOST_TEST_CONFIG_TEMPLATE", "${PythonBinaryHostTestConfigTemplate}") ctx.Strict("RUST_DEVICE_TEST_CONFIG_TEMPLATE", "${RustDeviceTestConfigTemplate}") ctx.Strict("RUST_HOST_TEST_CONFIG_TEMPLATE", "${RustHostTestConfigTemplate}") + ctx.Strict("RUST_DEVICE_BENCHMARK_CONFIG_TEMPLATE", "${RustDeviceBenchmarkConfigTemplate}") + ctx.Strict("RUST_HOST_BENCHMARK_CONFIG_TEMPLATE", "${RustHostBenchmarkConfigTemplate}") ctx.Strict("SHELL_TEST_CONFIG_TEMPLATE", "${ShellTestConfigTemplate}") ctx.Strict("EMPTY_TEST_CONFIG", "${EmptyTestConfig}") diff --git a/ui/build/soong.go b/ui/build/soong.go index 0089075a4..7e94b2589 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -21,6 +21,7 @@ import ( "strconv" "android/soong/shared" + "github.com/google/blueprint/deptools" soong_metrics_proto "android/soong/ui/metrics/metrics_proto" "github.com/google/blueprint" @@ -33,6 +34,11 @@ import ( "android/soong/ui/status" ) +const ( + availableEnvFile = "soong.environment.available" + usedEnvFile = "soong.environment.used" +) + func writeEnvironmentFile(ctx Context, envFile string, envDeps map[string]string) error { data, err := shared.EnvFileContents(envDeps) if err != nil { @@ -87,12 +93,23 @@ func (c BlueprintConfig) DebugCompilation() bool { return c.debugCompilation } -func bootstrapBlueprint(ctx Context, config Config) { +func environmentArgs(config Config, suffix string) []string { + return []string{ + "--available_env", shared.JoinPath(config.SoongOutDir(), availableEnvFile), + "--used_env", shared.JoinPath(config.SoongOutDir(), usedEnvFile+suffix), + } +} +func bootstrapBlueprint(ctx Context, config Config, integratedBp2Build bool) { ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap") defer ctx.EndTrace() var args bootstrap.Args + mainNinjaFile := shared.JoinPath(config.SoongOutDir(), "build.ninja") + globFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja") + bootstrapGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.ninja") + bootstrapDepFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d") + args.RunGoTests = !config.skipSoongTests args.UseValidations = true // Use validations to depend on tests args.BuildDir = config.SoongOutDir() @@ -100,8 +117,7 @@ func bootstrapBlueprint(ctx Context, config Config) { args.TopFile = "Android.bp" args.ModuleListFile = filepath.Join(config.FileListDir(), "Android.bp.list") args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja") - args.DepFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja.d") - args.GlobFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/soong-build-globs.ninja") + args.GlobFile = globFile args.GeneratingPrimaryBuilder = true args.DelveListen = os.Getenv("SOONG_DELVE") @@ -109,6 +125,44 @@ func bootstrapBlueprint(ctx Context, config Config) { args.DelvePath = shared.ResolveDelveBinary() } + commonArgs := bootstrap.PrimaryBuilderExtraFlags(args, bootstrapGlobFile, mainNinjaFile) + bp2BuildMarkerFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/bp2build_workspace_marker") + mainSoongBuildInputs := []string{"Android.bp"} + + if integratedBp2Build { + mainSoongBuildInputs = append(mainSoongBuildInputs, bp2BuildMarkerFile) + } + + soongBuildArgs := make([]string, 0) + soongBuildArgs = append(soongBuildArgs, commonArgs...) + soongBuildArgs = append(soongBuildArgs, environmentArgs(config, "")...) + soongBuildArgs = append(soongBuildArgs, "Android.bp") + + mainSoongBuildInvocation := bootstrap.PrimaryBuilderInvocation{ + Inputs: mainSoongBuildInputs, + Outputs: []string{mainNinjaFile}, + Args: soongBuildArgs, + } + + if integratedBp2Build { + bp2buildArgs := []string{"--bp2build_marker", bp2BuildMarkerFile} + bp2buildArgs = append(bp2buildArgs, commonArgs...) + bp2buildArgs = append(bp2buildArgs, environmentArgs(config, ".bp2build")...) + bp2buildArgs = append(bp2buildArgs, "Android.bp") + + bp2buildInvocation := bootstrap.PrimaryBuilderInvocation{ + Inputs: []string{"Android.bp"}, + Outputs: []string{bp2BuildMarkerFile}, + Args: bp2buildArgs, + } + args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{ + bp2buildInvocation, + mainSoongBuildInvocation, + } + } else { + args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{mainSoongBuildInvocation} + } + blueprintCtx := blueprint.NewContext() blueprintCtx.SetIgnoreUnknownModuleTypes(true) blueprintConfig := BlueprintConfig{ @@ -118,7 +172,21 @@ func bootstrapBlueprint(ctx Context, config Config) { debugCompilation: os.Getenv("SOONG_DELVE") != "", } - bootstrap.RunBlueprint(args, blueprintCtx, blueprintConfig) + bootstrapDeps := bootstrap.RunBlueprint(args, blueprintCtx, blueprintConfig) + err := deptools.WriteDepFile(bootstrapDepFile, args.OutFile, bootstrapDeps) + if err != nil { + ctx.Fatalf("Error writing depfile '%s': %s", bootstrapDepFile, err) + } +} + +func checkEnvironmentFile(currentEnv *Environment, envFile string) { + getenv := func(k string) string { + v, _ := currentEnv.Get(k) + return v + } + if stale, _ := shared.StaleEnvFile(envFile, getenv); stale { + os.Remove(envFile) + } } func runSoong(ctx Context, config Config) { @@ -129,7 +197,7 @@ func runSoong(ctx Context, config Config) { // .used with the ones that were actually used. The latter is used to // determine whether Soong needs to be re-run since why re-run it if only // unused variables were changed? - envFile := filepath.Join(config.SoongOutDir(), "soong.environment.available") + envFile := filepath.Join(config.SoongOutDir(), availableEnvFile) for _, n := range []string{".bootstrap", ".minibootstrap"} { dir := filepath.Join(config.SoongOutDir(), n) @@ -138,8 +206,10 @@ func runSoong(ctx Context, config Config) { } } + integratedBp2Build := config.Environment().IsEnvTrue("INTEGRATED_BP2BUILD") + // This is done unconditionally, but does not take a measurable amount of time - bootstrapBlueprint(ctx, config) + bootstrapBlueprint(ctx, config, integratedBp2Build) soongBuildEnv := config.Environment().Copy() soongBuildEnv.Set("TOP", os.Getenv("TOP")) @@ -164,13 +234,12 @@ func runSoong(ctx Context, config Config) { ctx.BeginTrace(metrics.RunSoong, "environment check") defer ctx.EndTrace() - envFile := filepath.Join(config.SoongOutDir(), "soong.environment.used") - getenv := func(k string) string { - v, _ := soongBuildEnv.Get(k) - return v - } - if stale, _ := shared.StaleEnvFile(envFile, getenv); stale { - os.Remove(envFile) + soongBuildEnvFile := filepath.Join(config.SoongOutDir(), usedEnvFile) + checkEnvironmentFile(soongBuildEnv, soongBuildEnvFile) + + if integratedBp2Build { + bp2buildEnvFile := filepath.Join(config.SoongOutDir(), usedEnvFile+".bp2build") + checkEnvironmentFile(soongBuildEnv, bp2buildEnvFile) } }() |