[automerger skipped] Allowlist SBOM generation tool so it can be used in Bazel. am: 9d307945be am: 0a3d198f5c am: ce5a279390 -s ours
am skip reason: Merged-In I4ad68b0613410f40c79ee24d3eef779c2ad57815 with SHA-1 9d307945be is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/build/soong/+/23305007
Change-Id: I58823a92006cac39d7b70b43ce111533fdd3e56b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/OWNERS b/OWNERS
index 964e27a..0234f27 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,7 +3,6 @@
# AMER
agespino@google.com
-alexmarquez@google.com
ccross@android.com
colefaust@google.com
cparsons@google.com
diff --git a/aidl_library/Android.bp b/aidl_library/Android.bp
new file mode 100644
index 0000000..ec21504
--- /dev/null
+++ b/aidl_library/Android.bp
@@ -0,0 +1,32 @@
+// Copyright 2023 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-aidl-library",
+ pkgPath: "android/soong/aidl_library",
+ deps: [
+ "soong-android",
+ ],
+ srcs: [
+ "aidl_library.go",
+ ],
+ testSrcs: [
+ "aidl_library_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/aidl_library/aidl_library.go b/aidl_library/aidl_library.go
new file mode 100644
index 0000000..8a84e6b
--- /dev/null
+++ b/aidl_library/aidl_library.go
@@ -0,0 +1,174 @@
+// Copyright 2023 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 aidl_library
+
+import (
+ "android/soong/android"
+ "android/soong/bazel"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+var PrepareForTestWithAidlLibrary = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+ registerAidlLibraryBuildComponents(ctx)
+})
+
+func init() {
+ registerAidlLibraryBuildComponents(android.InitRegistrationContext)
+}
+
+func registerAidlLibraryBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("aidl_library", AidlLibraryFactory)
+}
+
+type aidlLibraryProperties struct {
+ // srcs lists files that are included in this module for aidl compilation
+ Srcs []string `android:"path"`
+
+ // hdrs lists the headers that are imported by srcs but are not compiled by aidl to language binding code
+ // hdrs is provided to support Bazel migration. It is a no-op until
+ // we enable input sandbox in aidl compilation action
+ Hdrs []string `android:"path"`
+
+ // The prefix to strip from the paths of the .aidl files
+ // The remaining path is the package path of the aidl interface
+ Strip_import_prefix *string
+
+ // List of aidl files or aidl_library depended on by the module
+ Deps []string `android:"arch_variant"`
+}
+
+type AidlLibrary struct {
+ android.ModuleBase
+ android.BazelModuleBase
+ properties aidlLibraryProperties
+}
+
+type bazelAidlLibraryAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
+ Strip_import_prefix *string
+ Deps bazel.LabelListAttribute
+}
+
+func (lib *AidlLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ srcs := bazel.MakeLabelListAttribute(
+ android.BazelLabelForModuleSrc(
+ ctx,
+ lib.properties.Srcs,
+ ),
+ )
+
+ hdrs := bazel.MakeLabelListAttribute(
+ android.BazelLabelForModuleSrc(
+ ctx,
+ lib.properties.Hdrs,
+ ),
+ )
+
+ tags := []string{"apex_available=//apex_available:anyapex"}
+ deps := bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, lib.properties.Deps))
+
+ attrs := &bazelAidlLibraryAttributes{
+ Srcs: srcs,
+ Hdrs: hdrs,
+ Strip_import_prefix: lib.properties.Strip_import_prefix,
+ Deps: deps,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "aidl_library",
+ Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
+ }
+
+ ctx.CreateBazelTargetModule(
+ props,
+ android.CommonAttributes{
+ Name: lib.Name(),
+ Tags: bazel.MakeStringListAttribute(tags),
+ },
+ attrs,
+ )
+}
+
+type AidlLibraryInfo struct {
+ // The direct aidl files of the module
+ Srcs android.Paths
+ // The include dirs to the direct aidl files and those provided from aidl_library deps
+ IncludeDirs android.DepSet
+}
+
+// AidlLibraryProvider provides the srcs and the transitive include dirs
+var AidlLibraryProvider = blueprint.NewProvider(AidlLibraryInfo{})
+
+func (lib *AidlLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ includeDirsDepSetBuilder := android.NewDepSetBuilder(android.PREORDER)
+
+ if len(lib.properties.Srcs) == 0 && len(lib.properties.Hdrs) == 0 {
+ ctx.ModuleErrorf("at least srcs or hdrs prop must be non-empty")
+ }
+
+ srcs := android.PathsForModuleSrc(ctx, lib.properties.Srcs)
+ if lib.properties.Strip_import_prefix != nil {
+ srcs = android.PathsWithModuleSrcSubDir(
+ ctx,
+ srcs,
+ android.String(lib.properties.Strip_import_prefix))
+ }
+
+ includeDir := android.PathForModuleSrc(
+ ctx,
+ proptools.StringDefault(lib.properties.Strip_import_prefix, ""),
+ )
+
+ includeDirsDepSetBuilder.Direct(includeDir)
+
+ for _, dep := range ctx.GetDirectDepsWithTag(aidlLibraryTag) {
+ if ctx.OtherModuleHasProvider(dep, AidlLibraryProvider) {
+ info := ctx.OtherModuleProvider(dep, AidlLibraryProvider).(AidlLibraryInfo)
+ includeDirsDepSetBuilder.Transitive(&info.IncludeDirs)
+ }
+ }
+
+ // TODO(b/279960133) Propagate direct and transitive headers/srcs when aidl action sandboxes inputs
+ ctx.SetProvider(AidlLibraryProvider, AidlLibraryInfo{
+ Srcs: srcs,
+ IncludeDirs: *includeDirsDepSetBuilder.Build(),
+ })
+}
+
+// aidl_library contains a list of .aidl files and the strip_import_prefix to
+// to strip from the paths of the .aidl files. The sub-path left-over after stripping
+// corresponds to the aidl package path the aidl interfaces are scoped in
+func AidlLibraryFactory() android.Module {
+ module := &AidlLibrary{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidModule(module)
+ android.InitBazelModule(module)
+ return module
+}
+
+type aidlDependencyTag struct {
+ blueprint.BaseDependencyTag
+}
+
+var aidlLibraryTag = aidlDependencyTag{}
+
+func (lib *AidlLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+ for _, dep := range lib.properties.Deps {
+ ctx.AddDependency(lib, aidlLibraryTag, dep)
+ }
+}
diff --git a/aidl_library/aidl_library_test.go b/aidl_library/aidl_library_test.go
new file mode 100644
index 0000000..d9b410a
--- /dev/null
+++ b/aidl_library/aidl_library_test.go
@@ -0,0 +1,122 @@
+// Copyright 2023 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 aidl_library
+
+import (
+ "android/soong/android"
+ "testing"
+)
+
+func TestAidlLibrary(t *testing.T) {
+ t.Parallel()
+ ctx := android.GroupFixturePreparers(
+ PrepareForTestWithAidlLibrary,
+ android.MockFS{
+ "package_bar/Android.bp": []byte(`
+ aidl_library {
+ name: "bar",
+ srcs: ["x/y/Bar.aidl"],
+ strip_import_prefix: "x",
+ }
+ `),
+ }.AddToFixture(),
+ android.MockFS{
+ "package_foo/Android.bp": []byte(`
+ aidl_library {
+ name: "foo",
+ srcs: ["a/b/Foo.aidl"],
+ hdrs: ["Header.aidl"],
+ strip_import_prefix: "a",
+ deps: ["bar"],
+ }
+ `),
+ }.AddToFixture(),
+ ).RunTest(t).TestContext
+
+ foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
+ actualInfo := ctx.ModuleProvider(foo, AidlLibraryProvider).(AidlLibraryInfo)
+
+ android.AssertArrayString(
+ t,
+ "aidl include dirs",
+ []string{"package_foo/a", "package_bar/x"},
+ actualInfo.IncludeDirs.ToList().Strings(),
+ )
+
+ android.AssertPathsRelativeToTopEquals(
+ t,
+ "aidl srcs paths",
+ []string{"package_foo/a/b/Foo.aidl"},
+ actualInfo.Srcs,
+ )
+}
+
+func TestAidlLibraryWithoutStripImportPrefix(t *testing.T) {
+ t.Parallel()
+ ctx := android.GroupFixturePreparers(
+ PrepareForTestWithAidlLibrary,
+ android.MockFS{
+ "package_bar/Android.bp": []byte(`
+ aidl_library {
+ name: "bar",
+ srcs: ["x/y/Bar.aidl"],
+ }
+ `),
+ }.AddToFixture(),
+ android.MockFS{
+ "package_foo/Android.bp": []byte(`
+ aidl_library {
+ name: "foo",
+ srcs: ["a/b/Foo.aidl"],
+ hdrs: ["Header.aidl"],
+ deps: ["bar"],
+ }
+ `),
+ }.AddToFixture(),
+ ).RunTest(t).TestContext
+
+ foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
+ actualInfo := ctx.ModuleProvider(foo, AidlLibraryProvider).(AidlLibraryInfo)
+
+ android.AssertArrayString(
+ t,
+ "aidl include dirs",
+ []string{"package_foo", "package_bar"},
+ actualInfo.IncludeDirs.ToList().Strings(),
+ )
+
+ android.AssertPathsRelativeToTopEquals(
+ t,
+ "aidl srcs paths",
+ []string{"package_foo/a/b/Foo.aidl"},
+ actualInfo.Srcs,
+ )
+}
+
+func TestAidlLibraryWithNoSrcsHdrsDeps(t *testing.T) {
+ t.Parallel()
+ android.GroupFixturePreparers(
+ PrepareForTestWithAidlLibrary,
+ android.MockFS{
+ "package_bar/Android.bp": []byte(`
+ aidl_library {
+ name: "bar",
+ }
+ `),
+ }.AddToFixture(),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("at least srcs or hdrs prop must be non-empty")).
+ RunTest(t)
+}
diff --git a/android/Android.bp b/android/Android.bp
index 641c438..94d2c04 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -17,6 +17,7 @@
"soong-remoteexec",
"soong-response",
"soong-shared",
+ "soong-starlark",
"soong-starlark-format",
"soong-ui-metrics_proto",
"soong-android-allowlists",
@@ -60,7 +61,6 @@
"license_metadata.go",
"license_sdk_member.go",
"licenses.go",
- "makefile_goal.go",
"makevars.go",
"metrics.go",
"module.go",
@@ -77,6 +77,7 @@
"path_properties.go",
"paths.go",
"phony.go",
+ "plugin.go",
"prebuilt.go",
"prebuilt_build_tool.go",
"proto.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 63d4e11..e22eec5 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -38,7 +38,13 @@
// allows modules to opt-in.
Bp2BuildDefaultFalseRecursively
- DEFAULT_NINJA_WEIGHT = 1000
+ // Modules with build time of more than half a minute should have high priority.
+ DEFAULT_PRIORITIZED_WEIGHT = 1000
+ // Modules with build time of more than a few minute should have higher priority.
+ HIGH_PRIORITIZED_WEIGHT = 10 * DEFAULT_PRIORITIZED_WEIGHT
+ // Modules with inputs greater than the threshold should have high priority.
+ // Adjust this threshold if there are lots of wrong predictions.
+ INPUT_SIZE_THRESHOLD = 50
)
var (
@@ -79,6 +85,7 @@
"development/apps/DevelopmentSettings": Bp2BuildDefaultTrue,
"development/apps/Fallback": Bp2BuildDefaultTrue,
"development/apps/WidgetPreview": Bp2BuildDefaultTrue,
+ "development/python-packages/adb": Bp2BuildDefaultTrueRecursively,
"development/samples/BasicGLSurfaceView": Bp2BuildDefaultTrue,
"development/samples/BluetoothChat": Bp2BuildDefaultTrue,
"development/samples/BrokenKeyDerivation": Bp2BuildDefaultTrue,
@@ -185,6 +192,7 @@
"external/selinux/libselinux": Bp2BuildDefaultTrueRecursively,
"external/selinux/libsepol": Bp2BuildDefaultTrueRecursively,
"external/speex": Bp2BuildDefaultTrueRecursively,
+ "external/sqlite": Bp2BuildDefaultTrueRecursively,
"external/tinyalsa": Bp2BuildDefaultTrueRecursively,
"external/tinyalsa_new": Bp2BuildDefaultTrueRecursively,
"external/toybox": Bp2BuildDefaultTrueRecursively,
@@ -193,35 +201,40 @@
"external/zstd": Bp2BuildDefaultTrueRecursively,
"frameworks/av": Bp2BuildDefaultTrue,
+ "frameworks/av/media/audioaidlconversion": Bp2BuildDefaultTrueRecursively,
"frameworks/av/media/codec2/components/aom": Bp2BuildDefaultTrueRecursively,
"frameworks/av/media/codecs": Bp2BuildDefaultTrueRecursively,
"frameworks/av/media/liberror": Bp2BuildDefaultTrueRecursively,
+ "frameworks/av/media/libmediahelper": Bp2BuildDefaultTrue,
"frameworks/av/media/libshmem": Bp2BuildDefaultTrueRecursively,
- "frameworks/av/media/audioaidlconversion": Bp2BuildDefaultTrueRecursively,
+ "frameworks/av/media/module/codecs": Bp2BuildDefaultTrueRecursively,
+ "frameworks/av/media/module/foundation": Bp2BuildDefaultTrueRecursively,
"frameworks/av/media/module/minijail": Bp2BuildDefaultTrueRecursively,
"frameworks/av/services/minijail": Bp2BuildDefaultTrueRecursively,
"frameworks/base/libs/androidfw": Bp2BuildDefaultTrue,
+ "frameworks/base/libs/services": Bp2BuildDefaultTrue,
"frameworks/base/media/tests/MediaDump": Bp2BuildDefaultTrue,
- "frameworks/base/services/tests/servicestests/aidl": Bp2BuildDefaultTrue,
"frameworks/base/proto": Bp2BuildDefaultTrue,
+ "frameworks/base/services/tests/servicestests/aidl": Bp2BuildDefaultTrue,
"frameworks/base/startop/apps/test": Bp2BuildDefaultTrue,
"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
"frameworks/base/tools/aapt2": Bp2BuildDefaultTrue,
"frameworks/base/tools/codegen": Bp2BuildDefaultTrueRecursively,
"frameworks/base/tools/streaming_proto": Bp2BuildDefaultTrueRecursively,
"frameworks/hardware/interfaces/stats/aidl": Bp2BuildDefaultTrue,
+ "frameworks/libs/modules-utils/build": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/adbd_auth": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/arect": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/gui": Bp2BuildDefaultTrue,
"frameworks/native/libs/math": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/nativebase": Bp2BuildDefaultTrueRecursively,
+ "frameworks/native/libs/permission": Bp2BuildDefaultTrueRecursively,
"frameworks/native/libs/vr": Bp2BuildDefaultTrueRecursively,
"frameworks/native/opengl/tests/gl2_cameraeye": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/gl2_java": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/testLatency": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/testPauseResume": Bp2BuildDefaultTrue,
"frameworks/native/opengl/tests/testViewport": Bp2BuildDefaultTrue,
- "frameworks/native/libs/permission": Bp2BuildDefaultTrue,
"frameworks/native/services/batteryservice": Bp2BuildDefaultTrue,
"frameworks/proto_logging/stats": Bp2BuildDefaultTrueRecursively,
@@ -293,6 +306,7 @@
"packages/modules/Gki/libkver": Bp2BuildDefaultTrue,
"packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue,
"packages/modules/NeuralNetworks/apex": Bp2BuildDefaultTrue,
+ "packages/modules/NeuralNetworks/apex/testing": Bp2BuildDefaultTrue,
"packages/providers/MediaProvider/tools/dialogs": Bp2BuildDefaultFalse, // TODO(b/242834374)
"packages/screensavers/Basic": Bp2BuildDefaultTrue,
"packages/services/Car/tests/SampleRearViewCamera": Bp2BuildDefaultFalse, // TODO(b/242834321)
@@ -302,6 +316,7 @@
"prebuilts/clang/host/linux-x86": Bp2BuildDefaultTrueRecursively,
"prebuilts/gradle-plugin": Bp2BuildDefaultTrueRecursively,
"prebuilts/runtime/mainline/platform/sdk": Bp2BuildDefaultTrueRecursively,
+ "prebuilts/sdk": Bp2BuildDefaultTrue,
"prebuilts/sdk/current/androidx": Bp2BuildDefaultTrue,
"prebuilts/sdk/current/androidx-legacy": Bp2BuildDefaultTrue,
"prebuilts/sdk/current/extras/constraint-layout-x": Bp2BuildDefaultTrue,
@@ -446,10 +461,8 @@
"libidmap2_policies",
"libSurfaceFlingerProp",
// cc mainline modules
- "code_coverage.policy",
- "code_coverage.policy.other",
- "codec2_soft_exports",
- "codecs_g711dec",
+
+ // com.android.media.swcodec
"com.android.media.swcodec",
"com.android.media.swcodec-androidManifest",
"com.android.media.swcodec-ld.config.txt",
@@ -457,6 +470,12 @@
"com.android.media.swcodec-mediaswcodec.rc",
"com.android.media.swcodec.certificate",
"com.android.media.swcodec.key",
+ "test_com.android.media.swcodec",
+
+ // deps
+ "code_coverage.policy",
+ "code_coverage.policy.other",
+ "codec2_soft_exports",
"flatbuffer_headers",
"framework-connectivity-protos",
"gemmlowp_headers",
@@ -494,20 +513,6 @@
"libandroidio",
"libandroidio_srcs",
"libserviceutils",
- "libstagefright_amrnbenc",
- "libstagefright_amrnbdec",
- "libstagefright_amrwbdec",
- "libstagefright_amrwbenc",
- "libstagefright_amrnb_common",
- "libstagefright_enc_common",
- "libstagefright_flacdec",
- "libstagefright_foundation",
- "libstagefright_foundation_headers",
- "libstagefright_headers",
- "libstagefright_m4vh263dec",
- "libstagefright_m4vh263enc",
- "libstagefright_mp3dec",
- "libstagefright_mp3dec_headers",
"libsurfaceflinger_headers",
"libsync",
"libtextclassifier_hash_headers",
@@ -547,6 +552,14 @@
"liblp",
"libstorage_literals_headers",
+ "PluginCoreLib",
+ "dagger2",
+ "dagger2-android-annotation-stubs",
+ "dagger2-bootstrap-compiler",
+ "dagger2-producers",
+ "okio-lib",
+ "setupdesign-strings",
+
//external/avb
"avbtool",
"libavb",
@@ -559,6 +572,9 @@
//external/fec
"libfec_rs",
+ //frameworks/base/core/java
+ "IDropBoxManagerService_aidl",
+
//system/core/libsparse
"libsparse",
@@ -720,11 +736,12 @@
"api_fingerprint",
// allowlisting for kotlinx_coroutines
+ "annotations",
+ "kotlinx-coroutines-android-annotation-stubs",
+ "kotlinx-coroutines-core",
"kotlinx_coroutines",
"kotlinx_coroutines-device",
"kotlinx_coroutines-host",
- "annotations",
- "kotlinx-coroutines-android-annotation-stubs",
// for building com.android.neuralnetworks
"libimapper_stablec",
@@ -733,8 +750,16 @@
// min_sdk_version in android_app
"CtsShimUpgrade",
+ "art_cmdlineparser_headers",
+
// Mainline Module Apps
"CaptivePortalLogin",
+
+ "libstagefright_headers",
+
+ // aidl
+ "aidl",
+ "libaidl-common",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -766,7 +791,6 @@
"buffer_hub_queue_producer-test",
// cc bugs
- "libactivitymanager_aidl", // TODO(b/207426160): Unsupported use of aidl sources (via Dactivity_manager_procstate_aidl) in a cc_library
// TODO(b/198619163) module has same name as source
"logtagd.rc",
@@ -779,13 +803,12 @@
"libcutils_test_static",
"KernelLibcutilsTest",
- "linker", // TODO(b/228316882): cc_binary uses link_crt
- "versioner", // TODO(b/228313961): depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
- "art_libartbase_headers", // TODO(b/236268577): Header libraries do not support export_shared_libs_headers
- "apexer_test", // Requires aapt2
- "apexer_test_host_tools",
- "host_apex_verifier",
- "tjbench", // TODO(b/240563612): Stem property
+ "linker", // TODO(b/228316882): cc_binary uses link_crt
+ "versioner", // TODO(b/228313961): depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
+ "tjbench", // TODO(b/240563612): Stem property
+
+ // requires host tools for apexer
+ "apexer_test", "apexer_test_host_tools", "host_apex_verifier",
// java bugs
"libbase_ndk", // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
@@ -941,15 +964,18 @@
"libandroidfw_tests", "aapt2_tests", // failing due to data path issues
+ // error: overriding commands for target
+ // `out/host/linux-x86/nativetest64/gmock_tests/gmock_tests__cc_runner_test',
+ // previously defined at out/soong/installs-aosp_arm.mk:64919`
+ "gmock_tests",
+
// cc_test with unconverted deps, or are device-only (and not verified to pass yet)
"AMRWBEncTest",
- "AmrnbDecoderTest", // depends on unconverted modules: libaudioutils, libsndfile
- "AmrnbEncoderTest", // depends on unconverted modules: libaudioutils, libsndfile
- "AmrwbDecoderTest", // depends on unconverted modules: libsndfile, libaudioutils
- "AmrwbEncoderTest", // depends on unconverted modules: libaudioutils, libsndfile
- "Mp3DecoderTest", // depends on unconverted modules: libsndfile, libaudioutils
- "Mpeg4H263DecoderTest", // depends on unconverted modules: libstagefright_foundation
- "Mpeg4H263EncoderTest",
+ "AmrnbDecoderTest", // depends on unconverted modules: libaudioutils, libsndfile
+ "AmrnbEncoderTest", // depends on unconverted modules: libaudioutils, libsndfile
+ "AmrwbDecoderTest", // depends on unconverted modules: libsndfile, libaudioutils
+ "AmrwbEncoderTest", // depends on unconverted modules: libaudioutils, libsndfile
+ "Mp3DecoderTest", // depends on unconverted modules: libsndfile, libaudioutils
"avcdec",
"avcenc",
"bionic-benchmarks-tests",
@@ -1067,7 +1093,7 @@
"libcfi-test",
"libcfi-test-bad",
"libcrash_test",
- // "libcrypto_fuzz_unsafe",
+ "libcrypto_fuzz_unsafe",
"libdl_preempt_test_1",
"libdl_preempt_test_2",
"libdl_test_df_1_global",
@@ -1278,7 +1304,7 @@
"librelocations-fat",
"libsegment_gap_inner",
"libsegment_gap_outer",
- // "libssl_fuzz_unsafe",
+ "libssl_fuzz_unsafe",
"libstatssocket_private",
"libsysv-hash-table-library",
"libtest_atexit",
@@ -1430,6 +1456,10 @@
"CtsPkgInstallerConstants",
"guava-android-testlib",
+ "MetaDataBaseUnitTest", // depends on libstagefright
+ "AVCUtilsUnitTest", // depends on libstagefright
+ "ColorUtilsTest", // depends on libmediandk
+
// python_test_host with test data
"sbom_writers_test",
}
@@ -1521,6 +1551,11 @@
"adb_tls_connection_test",
// M9: mixed builds for mainline trains launch
"api_fingerprint",
+ // M11: neuralnetworks launch
+ "com.android.neuralnetworks",
+ "test_com.android.neuralnetworks",
+ "libneuralnetworks",
+ "libneuralnetworks_static",
}
// Staging-mode allowlist. Modules in this list are only built
@@ -1529,9 +1564,11 @@
// It is implicit that all modules in ProdMixedBuildsEnabledList will
// also be built - do not add them to this list.
StagingMixedBuildsEnabledList = []string{
- "com.android.neuralnetworks",
- "libneuralnetworks",
- "libneuralnetworks_static",
+ // M13: media.swcodec launch
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ "libstagefright_foundation",
+ "libcodec2_hidl@1.0",
}
// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
@@ -1550,267 +1587,12 @@
// "libstagefright_flacdec",
// "libutils",
- // TODO(b/273282046): Make this list customizable to support various targets.
- // The list of modules which are expected to spend lots of build time.
- // With `--ninja_weight_source=soong`, ninja builds these modules and deps first.
- HugeModulesMap = map[string]int{
- "AccountManagementApp": DEFAULT_NINJA_WEIGHT,
- "ActivityManagerPerfTestsStubApp1": DEFAULT_NINJA_WEIGHT,
- "ActivityManagerPerfTestsStubApp2": DEFAULT_NINJA_WEIGHT,
- "ActivityManagerPerfTestsStubApp3": DEFAULT_NINJA_WEIGHT,
- "api-stubs-docs-non-updatable": DEFAULT_NINJA_WEIGHT,
- "AppCompatibilityTest": DEFAULT_NINJA_WEIGHT,
- "AppTransitionTests": DEFAULT_NINJA_WEIGHT,
- "art_compiler_tests": DEFAULT_NINJA_WEIGHT,
- "art.module.intra.core.api.stubs.source": DEFAULT_NINJA_WEIGHT,
- "art.module.public.api.stubs.source": DEFAULT_NINJA_WEIGHT,
- "AttestationVerificationTest": DEFAULT_NINJA_WEIGHT,
- "BatteryUsageStatsProtoTests": DEFAULT_NINJA_WEIGHT,
- "bluetooth_test_gd_unit": DEFAULT_NINJA_WEIGHT,
- "Bluetooth": DEFAULT_NINJA_WEIGHT,
- "BluetoothInstrumentationTests": DEFAULT_NINJA_WEIGHT,
- "Calendar": DEFAULT_NINJA_WEIGHT,
- "CalendarProvider": DEFAULT_NINJA_WEIGHT,
- "Camera2": DEFAULT_NINJA_WEIGHT,
- "CarRotaryControllerUnitTests": DEFAULT_NINJA_WEIGHT,
- "CarSettingsForUnitTesting": DEFAULT_NINJA_WEIGHT,
- "CarSettingsUnitTests": DEFAULT_NINJA_WEIGHT,
- "CarSystemUI-tests": DEFAULT_NINJA_WEIGHT,
- "CellBroadcastApp": DEFAULT_NINJA_WEIGHT,
- "CellBroadcastLegacyApp": DEFAULT_NINJA_WEIGHT,
- "CellBroadcastReceiverOemUnitTests": DEFAULT_NINJA_WEIGHT,
- "CellBroadcastServiceModule": DEFAULT_NINJA_WEIGHT,
- "CompanionDeviceManager": DEFAULT_NINJA_WEIGHT,
- "ConnectivityChecker": DEFAULT_NINJA_WEIGHT,
- "Contacts": DEFAULT_NINJA_WEIGHT,
- "ContactsProvider": DEFAULT_NINJA_WEIGHT,
- "ContentCapturePerfTests": DEFAULT_NINJA_WEIGHT,
- "CorePerfTests": DEFAULT_NINJA_WEIGHT,
- "crosvm": DEFAULT_NINJA_WEIGHT,
- "CtsDomainVerificationDeviceMultiUserTestCases": DEFAULT_NINJA_WEIGHT,
- "CtsLogdTestCases": DEFAULT_NINJA_WEIGHT,
- "CtsMediaProviderTranscodeTests": DEFAULT_NINJA_WEIGHT,
- "CtsRollbackManagerHostTestHelperApp": DEFAULT_NINJA_WEIGHT,
- "CtsRollbackManagerHostTestHelperApp2": DEFAULT_NINJA_WEIGHT,
- "CtsRootPackageInstallerTestCases": DEFAULT_NINJA_WEIGHT,
- "CtsRootRollbackManagerHostTestHelperApp": DEFAULT_NINJA_WEIGHT,
- "CtsTranscodeTestAppSupportsHevc": DEFAULT_NINJA_WEIGHT,
- "CtsTranscodeTestAppSupportsSlowMotion": DEFAULT_NINJA_WEIGHT,
- "CuttlefishDisplayHotplugHelperApp": DEFAULT_NINJA_WEIGHT,
- "cvd-host_package": DEFAULT_NINJA_WEIGHT,
- "DelegateTestApp": DEFAULT_NINJA_WEIGHT,
- "DeskClock": DEFAULT_NINJA_WEIGHT,
- "Development": DEFAULT_NINJA_WEIGHT,
- "DeviceAdminTestApp": DEFAULT_NINJA_WEIGHT,
- "DevicePolicyManagementRoleHolderTestApp": DEFAULT_NINJA_WEIGHT,
- "dex2oatd": DEFAULT_NINJA_WEIGHT,
- "DocumentsUI": DEFAULT_NINJA_WEIGHT,
- "EasterEgg": DEFAULT_NINJA_WEIGHT,
- "EffectProxyTest": DEFAULT_NINJA_WEIGHT,
- "EmergencyInfo": DEFAULT_NINJA_WEIGHT,
- "EmptyTestApp": DEFAULT_NINJA_WEIGHT,
- "ExtServices": DEFAULT_NINJA_WEIGHT,
- "FacebookAppsScenarioTests": DEFAULT_NINJA_WEIGHT,
- "flickerlib-core": DEFAULT_NINJA_WEIGHT,
- "flickerlib": DEFAULT_NINJA_WEIGHT,
- "FlickerLibTest": DEFAULT_NINJA_WEIGHT,
- "FlickerTests": DEFAULT_NINJA_WEIGHT,
- "framework-minus-apex": DEFAULT_NINJA_WEIGHT,
- "framework-res": DEFAULT_NINJA_WEIGHT,
- "FrameworksCoreTests": DEFAULT_NINJA_WEIGHT,
- "FrameworksMockingCoreTests": DEFAULT_NINJA_WEIGHT,
- "FrameworksMockingServicesTests": DEFAULT_NINJA_WEIGHT,
- "FrameworksNetSmokeTests": DEFAULT_NINJA_WEIGHT,
- "FrameworksNetTests": DEFAULT_NINJA_WEIGHT,
- "FrameworksServicesTests": DEFAULT_NINJA_WEIGHT,
- "FrameworksTelephonyTests": DEFAULT_NINJA_WEIGHT,
- "FrameworksUiServicesTests": DEFAULT_NINJA_WEIGHT,
- "FrameworksVcnTests": DEFAULT_NINJA_WEIGHT,
- "Gallery2": DEFAULT_NINJA_WEIGHT,
- "GameCoreDevice": DEFAULT_NINJA_WEIGHT,
- "GoogleBluetoothInstrumentationTests": DEFAULT_NINJA_WEIGHT,
- "guice_munged_srcs": DEFAULT_NINJA_WEIGHT,
- "HalfSheetUX": DEFAULT_NINJA_WEIGHT,
- "ImePerfTests": DEFAULT_NINJA_WEIGHT,
- "imgdiag": DEFAULT_NINJA_WEIGHT,
- "ImsServiceEntitlement": DEFAULT_NINJA_WEIGHT,
- "ImsServiceEntitlementUnitTests": DEFAULT_NINJA_WEIGHT,
- "InputTests": DEFAULT_NINJA_WEIGHT,
- "InstallTest": DEFAULT_NINJA_WEIGHT,
- "IntentResolver": DEFAULT_NINJA_WEIGHT,
- "JankBench": DEFAULT_NINJA_WEIGHT,
- "jsilver": DEFAULT_NINJA_WEIGHT,
- "KeyChain": DEFAULT_NINJA_WEIGHT,
- "KeyChainTests": DEFAULT_NINJA_WEIGHT,
- "keystore2": DEFAULT_NINJA_WEIGHT,
- "LargeResourcesCompressed": DEFAULT_NINJA_WEIGHT,
- "LatinIME": DEFAULT_NINJA_WEIGHT,
- "Launcher3QuickStepLib": DEFAULT_NINJA_WEIGHT,
- "libaom": DEFAULT_NINJA_WEIGHT,
- "libart-broken": DEFAULT_NINJA_WEIGHT,
- "libart-compiler": DEFAULT_NINJA_WEIGHT,
- "libart-disassembler": DEFAULT_NINJA_WEIGHT,
- "libart": DEFAULT_NINJA_WEIGHT,
- "libartd": DEFAULT_NINJA_WEIGHT,
- "libaudiohal@7.1": DEFAULT_NINJA_WEIGHT,
- "libbluetooth_core_rs": DEFAULT_NINJA_WEIGHT,
- "libbluetooth_gd_unit_tests": DEFAULT_NINJA_WEIGHT,
- "libbluetooth_gd": DEFAULT_NINJA_WEIGHT,
- "libbluetooth_rs": DEFAULT_NINJA_WEIGHT,
- "libbluetooth-for-tests": DEFAULT_NINJA_WEIGHT,
- "libbt_common": DEFAULT_NINJA_WEIGHT,
- "libbt_packets_nonapex": DEFAULT_NINJA_WEIGHT,
- "libbt_packets": DEFAULT_NINJA_WEIGHT,
- "libbt_shim_ffi": DEFAULT_NINJA_WEIGHT,
- "libbt_shim": DEFAULT_NINJA_WEIGHT,
- "libbt-audio-hal-interface": DEFAULT_NINJA_WEIGHT,
- "libbt-bta-core": DEFAULT_NINJA_WEIGHT,
- "libbt-bta": DEFAULT_NINJA_WEIGHT,
- "libbt-common": DEFAULT_NINJA_WEIGHT,
- "libbt-hci": DEFAULT_NINJA_WEIGHT,
- "libbt-platform-protos-lite": DEFAULT_NINJA_WEIGHT,
- "libbt-protos-lite": DEFAULT_NINJA_WEIGHT,
- "libbt-sbc-decoder": DEFAULT_NINJA_WEIGHT,
- "libc": DEFAULT_NINJA_WEIGHT,
- "libclap": DEFAULT_NINJA_WEIGHT,
- "libcodec2_soft_av1dec_gav1": DEFAULT_NINJA_WEIGHT,
- "libcompositionengine_test": DEFAULT_NINJA_WEIGHT,
- "libdevices": DEFAULT_NINJA_WEIGHT,
- "libfrontend_proto": DEFAULT_NINJA_WEIGHT,
- "libhwtrust": DEFAULT_NINJA_WEIGHT,
- "libjni": DEFAULT_NINJA_WEIGHT,
- "libkeystore2": DEFAULT_NINJA_WEIGHT,
- "libkmr_ta": DEFAULT_NINJA_WEIGHT,
- "liblmp": DEFAULT_NINJA_WEIGHT,
- "libopenjdkjvmtid": DEFAULT_NINJA_WEIGHT,
- "libprotobuf_deprecated": DEFAULT_NINJA_WEIGHT,
- "libprotobuf": DEFAULT_NINJA_WEIGHT,
- "libregex": DEFAULT_NINJA_WEIGHT,
- "LibStatsPullTests": DEFAULT_NINJA_WEIGHT,
- "libstd": DEFAULT_NINJA_WEIGHT,
- "libsurfaceflinger_unittest": DEFAULT_NINJA_WEIGHT,
- "libsyn": DEFAULT_NINJA_WEIGHT,
- "libtokio": DEFAULT_NINJA_WEIGHT,
- "libuwb_core": DEFAULT_NINJA_WEIGHT,
- "libuwb_uci_jni_rust": DEFAULT_NINJA_WEIGHT,
- "libuwb_uci_packets": DEFAULT_NINJA_WEIGHT,
- "libvpx": DEFAULT_NINJA_WEIGHT,
- "libvulkan_enc": DEFAULT_NINJA_WEIGHT,
- "libwebrtc": DEFAULT_NINJA_WEIGHT,
- "LiveWallpapersPicker": DEFAULT_NINJA_WEIGHT,
- "LockTaskApp": DEFAULT_NINJA_WEIGHT,
- "LongevityPlatformLibTests": DEFAULT_NINJA_WEIGHT,
- "ManagedProvisioning": DEFAULT_NINJA_WEIGHT,
- "ManagedProvisioningTests": DEFAULT_NINJA_WEIGHT,
- "MediaProvider": DEFAULT_NINJA_WEIGHT,
- "MediaProviderClientTests": DEFAULT_NINJA_WEIGHT,
- "MediaProviderLegacy": DEFAULT_NINJA_WEIGHT,
- "messaging": DEFAULT_NINJA_WEIGHT,
- "metalava": DEFAULT_NINJA_WEIGHT,
- "MicrobenchmarkRunnerTests": DEFAULT_NINJA_WEIGHT,
- "microdroid_manager": DEFAULT_NINJA_WEIGHT,
- "minikin_tests": DEFAULT_NINJA_WEIGHT,
- "MLCTestApp": DEFAULT_NINJA_WEIGHT,
- "MmsService": DEFAULT_NINJA_WEIGHT,
- "MmsServiceTests": DEFAULT_NINJA_WEIGHT,
- "module-lib-api-stubs-docs-non-updatable": DEFAULT_NINJA_WEIGHT,
- "motion_tool_lib_tests": DEFAULT_NINJA_WEIGHT,
- "MtpService": DEFAULT_NINJA_WEIGHT,
- "MultiUserTests": DEFAULT_NINJA_WEIGHT,
- "NearbyIntegrationUiTests": DEFAULT_NINJA_WEIGHT,
- "net_test_bluetooth": DEFAULT_NINJA_WEIGHT,
- "net_test_btif": DEFAULT_NINJA_WEIGHT,
- "net_test_main_shim": DEFAULT_NINJA_WEIGHT,
- "net_test_stack": DEFAULT_NINJA_WEIGHT,
- "net-tests-utils": DEFAULT_NINJA_WEIGHT,
- "NetworkStackCoverageTests": DEFAULT_NINJA_WEIGHT,
- "NetworkStackIntegrationTests": DEFAULT_NINJA_WEIGHT,
- "NetworkStackNext": DEFAULT_NINJA_WEIGHT,
- "NfcNci": DEFAULT_NINJA_WEIGHT,
- "NfcNciUnitTests": DEFAULT_NINJA_WEIGHT,
- "NotEmptyTestApp": DEFAULT_NINJA_WEIGHT,
- "NotificationFunctionalTests": DEFAULT_NINJA_WEIGHT,
- "oatdumpd": DEFAULT_NINJA_WEIGHT,
- "OsuLogin": DEFAULT_NINJA_WEIGHT,
- "PackageInstaller": DEFAULT_NINJA_WEIGHT,
- "PackageManagerComponentOverrideTests": DEFAULT_NINJA_WEIGHT,
- "PackageManagerPerfTests": DEFAULT_NINJA_WEIGHT,
- "PackageManagerServiceServerTests": DEFAULT_NINJA_WEIGHT,
- "PackageManagerServiceUnitTests": DEFAULT_NINJA_WEIGHT,
- "PackageWatchdogTest": DEFAULT_NINJA_WEIGHT,
- "PandoraServerLib": DEFAULT_NINJA_WEIGHT,
- "pdl": DEFAULT_NINJA_WEIGHT,
- "perfetto_trace_java_protos": DEFAULT_NINJA_WEIGHT,
- "perfetto_trace-full": DEFAULT_NINJA_WEIGHT,
- "PermissionController": DEFAULT_NINJA_WEIGHT,
- "PermissionControllerMockingTests": DEFAULT_NINJA_WEIGHT,
- "PixelAppCompTests": DEFAULT_NINJA_WEIGHT,
- "platform-bootclasspath": DEFAULT_NINJA_WEIGHT,
- "PlatformCommonScenarioTests": DEFAULT_NINJA_WEIGHT,
- "PlatformComposeCoreTests": DEFAULT_NINJA_WEIGHT,
- "platformprotoslite": DEFAULT_NINJA_WEIGHT,
- "PlatformRuleTests": DEFAULT_NINJA_WEIGHT,
- "precompiled_sepolicy-without_apex": DEFAULT_NINJA_WEIGHT,
- "PresencePolling": DEFAULT_NINJA_WEIGHT,
- "PrintSpooler": DEFAULT_NINJA_WEIGHT,
- "QuickSearchBox": DEFAULT_NINJA_WEIGHT,
- "RemoteDPCTestApp": DEFAULT_NINJA_WEIGHT,
- "RemoteProvisioningServiceTests": DEFAULT_NINJA_WEIGHT,
- "RkpdAppUnitTests": DEFAULT_NINJA_WEIGHT,
- "Robolectric_shadows_framework": DEFAULT_NINJA_WEIGHT,
- "RoleHolderApp": DEFAULT_NINJA_WEIGHT,
- "SdkSandbox": DEFAULT_NINJA_WEIGHT,
- "service-appsearch": DEFAULT_NINJA_WEIGHT,
- "service-connectivity": DEFAULT_NINJA_WEIGHT,
- "service-uwb": DEFAULT_NINJA_WEIGHT,
- "service-wifi": DEFAULT_NINJA_WEIGHT,
- "services-non-updatable-stubs": DEFAULT_NINJA_WEIGHT,
- "services": DEFAULT_NINJA_WEIGHT,
- "Settings-core": DEFAULT_NINJA_WEIGHT,
- "Settings": DEFAULT_NINJA_WEIGHT,
- "SettingsIntelligence": DEFAULT_NINJA_WEIGHT,
- "SettingsLibTests": DEFAULT_NINJA_WEIGHT,
- "SettingsProvider": DEFAULT_NINJA_WEIGHT,
- "Shell": DEFAULT_NINJA_WEIGHT,
- "SimAppDialog": DEFAULT_NINJA_WEIGHT,
- "sl4a": DEFAULT_NINJA_WEIGHT,
- "SmsApp": DEFAULT_NINJA_WEIGHT,
- "SoundPicker": DEFAULT_NINJA_WEIGHT,
- "StagedInstallTest": DEFAULT_NINJA_WEIGHT,
- "StatementService": DEFAULT_NINJA_WEIGHT,
- "StatsdFrameworkTestApp": DEFAULT_NINJA_WEIGHT,
- "StatsdFrameworkTestAppNoPermission": DEFAULT_NINJA_WEIGHT,
- "statsdprotolite": DEFAULT_NINJA_WEIGHT,
- "Stk": DEFAULT_NINJA_WEIGHT,
- "StorageManager": DEFAULT_NINJA_WEIGHT,
- "system-api-stubs-docs-non-updatable": DEFAULT_NINJA_WEIGHT,
- "SystemUI-core": DEFAULT_NINJA_WEIGHT,
- "SystemUI-tests-base": DEFAULT_NINJA_WEIGHT,
- "SystemUI-tests": DEFAULT_NINJA_WEIGHT,
- "SystemUI": DEFAULT_NINJA_WEIGHT,
- "SystemUIComposeFeatures": DEFAULT_NINJA_WEIGHT,
- "SystemUIComposeFeaturesTests": DEFAULT_NINJA_WEIGHT,
- "SystemUITests": DEFAULT_NINJA_WEIGHT,
- "Tag": DEFAULT_NINJA_WEIGHT,
- "Telecom": DEFAULT_NINJA_WEIGHT,
- "TelecomUnitTests": DEFAULT_NINJA_WEIGHT,
- "telephony-common": DEFAULT_NINJA_WEIGHT,
- "TelephonyProvider": DEFAULT_NINJA_WEIGHT,
- "TeleService": DEFAULT_NINJA_WEIGHT,
- "test-api-stubs-docs-non-updatable": DEFAULT_NINJA_WEIGHT,
- "TetheringIntegrationTests": DEFAULT_NINJA_WEIGHT,
- "TetheringNext": DEFAULT_NINJA_WEIGHT,
- "ThemePickerTests": DEFAULT_NINJA_WEIGHT,
- "Traceur": DEFAULT_NINJA_WEIGHT,
- "UsbManagerTests": DEFAULT_NINJA_WEIGHT,
- "UsbTests": DEFAULT_NINJA_WEIGHT,
- "virtmgr": DEFAULT_NINJA_WEIGHT,
- "WallpaperPicker2TestLib": DEFAULT_NINJA_WEIGHT,
- "WallpaperPicker2Tests": DEFAULT_NINJA_WEIGHT,
- "WifiDialog": DEFAULT_NINJA_WEIGHT,
- "wm-proto-parsers": DEFAULT_NINJA_WEIGHT,
- "WMShellFlickerTests": DEFAULT_NINJA_WEIGHT,
- "WmTests": DEFAULT_NINJA_WEIGHT,
- "wpa_supplicant": DEFAULT_NINJA_WEIGHT,
+ // The list of module types which are expected to spend lots of build time.
+ // With `--ninja_weight_source=soong`, ninja builds these module types and deps first.
+ HugeModuleTypePrefixMap = map[string]int{
+ "rust_": HIGH_PRIORITIZED_WEIGHT,
+ "droidstubs": DEFAULT_PRIORITIZED_WEIGHT,
+ "art_": DEFAULT_PRIORITIZED_WEIGHT,
+ "ndk_library": DEFAULT_PRIORITIZED_WEIGHT,
}
)
diff --git a/android/apex.go b/android/apex.go
index c9b4a0b..253a1a9 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -84,6 +84,9 @@
//
// See Prebuilt.ApexInfoMutator for more information.
ForPrebuiltApex bool
+
+ // Returns the name of the test apexes that this module is included in.
+ TestApexes []string
}
var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
@@ -287,6 +290,9 @@
// See ApexModule.UniqueApexVariants()
UniqueApexVariationsForDeps bool `blueprint:"mutated"`
+
+ // The test apexes that includes this apex variant
+ TestApexes []string `blueprint:"mutated"`
}
// Marker interface that identifies dependencies that are excluded from APEX contents.
@@ -429,6 +435,11 @@
return nil
}
+// Returns the test apexes that this module is included in.
+func (m *ApexModuleBase) TestApexes() []string {
+ return m.ApexProperties.TestApexes
+}
+
// Implements ApexModule
func (m *ApexModuleBase) UniqueApexVariations() bool {
// If needed, this will bel overridden by concrete types inheriting
@@ -451,6 +462,14 @@
AvailableToGkiApex = "com.android.gki.*"
)
+var (
+ AvailableToRecognziedWildcards = []string{
+ AvailableToPlatform,
+ AvailableToAnyApex,
+ AvailableToGkiApex,
+ }
+)
+
// CheckAvailableForApex provides the default algorithm for checking the apex availability. When the
// availability is empty, it defaults to ["//apex_available:platform"] which means "available to the
// platform but not available to any APEX". When the list is not empty, `what` is matched against
@@ -551,12 +570,14 @@
// Platform APIs is allowed for this module only when all APEXes containing
// the module are with `use_platform_apis: true`.
merged[index].UsePlatformApis = merged[index].UsePlatformApis && apexInfo.UsePlatformApis
+ merged[index].TestApexes = append(merged[index].TestApexes, apexInfo.TestApexes...)
} else {
seen[mergedName] = len(merged)
apexInfo.ApexVariationName = mergedName
apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
+ apexInfo.TestApexes = CopyOf(apexInfo.TestApexes)
merged = append(merged, apexInfo)
}
aliases = append(aliases, [2]string{variantName, mergedName})
@@ -604,8 +625,10 @@
mctx.SetDefaultDependencyVariation(&defaultVariation)
variations := []string{defaultVariation}
+ testApexes := []string{}
for _, a := range apexInfos {
variations = append(variations, a.ApexVariationName)
+ testApexes = append(testApexes, a.TestApexes...)
}
modules := mctx.CreateVariations(variations...)
for i, mod := range modules {
@@ -619,6 +642,9 @@
if !platformVariation {
mctx.SetVariationProvider(mod, ApexInfoProvider, apexInfos[i-1])
}
+ // Set the value of TestApexes in every single apex variant.
+ // This allows each apex variant to be aware of the test apexes in the user provided apex_available.
+ mod.(ApexModule).apexModuleBase().ApexProperties.TestApexes = testApexes
}
for _, alias := range aliases {
@@ -909,3 +935,9 @@
return true
})
}
+
+// Implemented by apexBundle.
+type ApexTestInterface interface {
+ // Return true if the apex bundle is an apex_test
+ IsTestApex() bool
+}
diff --git a/android/apex_test.go b/android/apex_test.go
index 0bf4c9c..ddc730d 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
{
name: "single",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"foo", "apex10000"},
@@ -45,11 +45,11 @@
{
name: "merge",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
+ {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false, nil}},
wantAliases: [][2]string{
{"bar", "apex10000"},
{"foo", "apex10000"},
@@ -58,12 +58,12 @@
{
name: "don't merge version",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+ {"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex30"},
@@ -73,11 +73,11 @@
{
name: "merge updatable",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -87,15 +87,15 @@
{
name: "don't merge when for prebuilt_apex",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
// This one should not be merged in with the others because it is for
// a prebuilt_apex.
- {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+ {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
- {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
+ {"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -105,11 +105,11 @@
{
name: "merge different UsePlatformApis but don't allow using platform api",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -119,11 +119,11 @@
{
name: "merge same UsePlatformApis and allow using platform api",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+ {"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
diff --git a/android/api_levels.go b/android/api_levels.go
index 137fd9d..fa919fd 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -15,12 +15,10 @@
package android
import (
+ "android/soong/starlark_import"
"encoding/json"
"fmt"
"strconv"
-
- "android/soong/bazel"
- "android/soong/starlark_fmt"
)
func init() {
@@ -288,13 +286,17 @@
// ReplaceFinalizedCodenames returns the API level number associated with that API level
// if the `raw` input is the codename of an API level has been finalized.
// If the input is *not* a finalized codename, the input is returned unmodified.
-func ReplaceFinalizedCodenames(config Config, raw string) string {
- num, ok := getFinalCodenamesMap(config)[raw]
+func ReplaceFinalizedCodenames(config Config, raw string) (string, error) {
+ finalCodenamesMap, err := getFinalCodenamesMap(config)
+ if err != nil {
+ return raw, err
+ }
+ num, ok := finalCodenamesMap[raw]
if !ok {
- return raw
+ return raw, nil
}
- return strconv.Itoa(num)
+ return strconv.Itoa(num), nil
}
// ApiLevelFrom converts the given string `raw` to an ApiLevel.
@@ -344,7 +346,11 @@
}
}
- canonical, ok := getApiLevelsMapReleasedVersions()[raw]
+ apiLevelsReleasedVersions, err := getApiLevelsMapReleasedVersions()
+ if err != nil {
+ return NoneApiLevel, err
+ }
+ canonical, ok := apiLevelsReleasedVersions[raw]
if !ok {
asInt, err := strconv.Atoi(raw)
if err != nil {
@@ -410,38 +416,21 @@
return PathForOutput(ctx, "api_levels.json")
}
-func getApiLevelsMapReleasedVersions() map[string]int {
- return map[string]int{
- "G": 9,
- "I": 14,
- "J": 16,
- "J-MR1": 17,
- "J-MR2": 18,
- "K": 19,
- "L": 21,
- "L-MR1": 22,
- "M": 23,
- "N": 24,
- "N-MR1": 25,
- "O": 26,
- "O-MR1": 27,
- "P": 28,
- "Q": 29,
- "R": 30,
- "S": 31,
- "S-V2": 32,
- "Tiramisu": 33,
- "UpsideDownCake": 34,
- }
+func getApiLevelsMapReleasedVersions() (map[string]int, error) {
+ return starlark_import.GetStarlarkValue[map[string]int]("api_levels_released_versions")
}
var finalCodenamesMapKey = NewOnceKey("FinalCodenamesMap")
-func getFinalCodenamesMap(config Config) map[string]int {
+func getFinalCodenamesMap(config Config) (map[string]int, error) {
+ type resultStruct struct {
+ result map[string]int
+ err error
+ }
// This logic is replicated in starlark, if changing logic here update starlark code too
// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=30;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
- return config.Once(finalCodenamesMapKey, func() interface{} {
- apiLevelsMap := getApiLevelsMapReleasedVersions()
+ result := config.Once(finalCodenamesMapKey, func() interface{} {
+ apiLevelsMap, err := getApiLevelsMapReleasedVersions()
// TODO: Differentiate "current" and "future".
// The code base calls it FutureApiLevel, but the spelling is "current",
@@ -454,41 +443,44 @@
// added in S, both of these are usable when building for "current" when
// neither R nor S are final, but the S APIs stop being available in a
// final R build.
- if Bool(config.productVariables.Platform_sdk_final) {
+ if err == nil && Bool(config.productVariables.Platform_sdk_final) {
apiLevelsMap["current"] = config.PlatformSdkVersion().FinalOrFutureInt()
}
- return apiLevelsMap
- }).(map[string]int)
+ return resultStruct{apiLevelsMap, err}
+ }).(resultStruct)
+ return result.result, result.err
}
var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
// ApiLevelsMap has entries for preview API levels
-func GetApiLevelsMap(config Config) map[string]int {
+func GetApiLevelsMap(config Config) (map[string]int, error) {
+ type resultStruct struct {
+ result map[string]int
+ err error
+ }
// This logic is replicated in starlark, if changing logic here update starlark code too
// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=23;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
- return config.Once(apiLevelsMapKey, func() interface{} {
- apiLevelsMap := getApiLevelsMapReleasedVersions()
- for i, codename := range config.PlatformVersionAllPreviewCodenames() {
- apiLevelsMap[codename] = previewAPILevelBase + i
+ result := config.Once(apiLevelsMapKey, func() interface{} {
+ apiLevelsMap, err := getApiLevelsMapReleasedVersions()
+ if err == nil {
+ for i, codename := range config.PlatformVersionAllPreviewCodenames() {
+ apiLevelsMap[codename] = previewAPILevelBase + i
+ }
}
- return apiLevelsMap
- }).(map[string]int)
+ return resultStruct{apiLevelsMap, err}
+ }).(resultStruct)
+ return result.result, result.err
}
func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
- apiLevelsMap := GetApiLevelsMap(ctx.Config())
+ apiLevelsMap, err := GetApiLevelsMap(ctx.Config())
+ if err != nil {
+ ctx.Errorf("%s\n", err)
+ return
+ }
apiLevelsJson := GetApiLevelsJson(ctx)
createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap)
}
-
-func StarlarkApiLevelConfigs(config Config) string {
- return fmt.Sprintf(bazel.GeneratedBazelFileWarning+`
-_api_levels_released_versions = %s
-
-api_levels_released_versions = _api_levels_released_versions
-`, starlark_fmt.PrintStringIntDict(getApiLevelsMapReleasedVersions(), 0),
- )
-}
diff --git a/android/bazel.go b/android/bazel.go
index 1646883..114b1f5 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -32,6 +32,22 @@
Bp2BuildTopLevel = "."
)
+type MixedBuildEnabledStatus int
+
+const (
+ // This module can be mixed_built.
+ MixedBuildEnabled = iota
+
+ // There is a technical incompatibility preventing this module from being
+ // bazel-analyzed. Note: the module might also be incompatible.
+ TechnicalIncompatibility
+
+ // This module cannot be mixed_built due to some incompatibility with it
+ // that is not a platform incompatibility. Example: the module-type is not
+ // enabled, or is not bp2build-converted.
+ ModuleIncompatibility
+)
+
// FileGroupAsLibrary describes a filegroup module that is converted to some library
// such as aidl_library or proto_library.
type FileGroupAsLibrary interface {
@@ -55,7 +71,7 @@
MissingDeps []string `blueprint:"mutated"`
}
-type bazelModuleProperties struct {
+type BazelModuleProperties struct {
// The label of the Bazel target replacing this Soong module. When run in conversion mode, this
// will import the handcrafted build target into the autogenerated file. Note: this may result in
// a conflict due to duplicate targets if bp2build_available is also set.
@@ -80,7 +96,7 @@
type properties struct {
// In "Bazel mixed build" mode, this represents the Bazel target replacing
// this Soong module.
- Bazel_module bazelModuleProperties
+ Bazel_module BazelModuleProperties
}
// namespacedVariableProperties is a map from a string representing a Soong
@@ -346,24 +362,31 @@
}).(Bp2BuildConversionAllowlist)
}
-// MixedBuildsEnabled returns true if a module is ready to be replaced by a
-// converted or handcrafted Bazel target. As a side effect, calling this
-// method will also log whether this module is mixed build enabled for
-// metrics reporting.
-func MixedBuildsEnabled(ctx BaseModuleContext) bool {
+// MixedBuildsEnabled returns a MixedBuildEnabledStatus regarding whether
+// a module is ready to be replaced by a converted or handcrafted Bazel target.
+// As a side effect, calling this method will also log whether this module is
+// mixed build enabled for metrics reporting.
+func MixedBuildsEnabled(ctx BaseModuleContext) MixedBuildEnabledStatus {
module := ctx.Module()
apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
withinApex := !apexInfo.IsForPlatform()
+
+ platformIncompatible := isPlatformIncompatible(ctx.Os(), ctx.Arch().ArchType)
+ if platformIncompatible {
+ ctx.Config().LogMixedBuild(ctx, false)
+ return TechnicalIncompatibility
+ }
+
mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
- ctx.Os() != Windows && // Windows toolchains are not currently supported.
- ctx.Os() != LinuxBionic && // Linux Bionic toolchains are not currently supported.
- ctx.Os() != LinuxMusl && // Linux musl toolchains are not currently supported (b/259266326).
- ctx.Arch().ArchType != Riscv64 && // TODO(b/262192655) Riscv64 toolchains are not currently supported.
module.Enabled() &&
convertedToBazel(ctx, module) &&
ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex)
ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
- return mixedBuildEnabled
+
+ if mixedBuildEnabled {
+ return MixedBuildEnabled
+ }
+ return ModuleIncompatibility
}
// ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
@@ -388,6 +411,13 @@
OtherModuleDir(m blueprint.Module) string
}
+func isPlatformIncompatible(osType OsType, arch ArchType) bool {
+ return osType == Windows || // Windows toolchains are not currently supported.
+ osType == LinuxBionic || // Linux Bionic toolchains are not currently supported.
+ osType == LinuxMusl || // Linux musl toolchains are not currently supported (b/259266326).
+ arch == Riscv64 // TODO(b/262192655) Riscv64 toolchains are not currently supported.
+}
+
func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool {
if !b.bazelProps().Bazel_module.CanConvertToBazel {
return false
@@ -401,7 +431,7 @@
}
propValue := b.bazelProperties.Bazel_module.Bp2build_available
- packagePath := ctx.OtherModuleDir(module)
+ packagePath := moduleDirWithPossibleOverride(ctx, module)
// Modules in unit tests which are enabled in the allowlist by type or name
// trigger this conditional because unit tests run under the "." package path
@@ -410,7 +440,7 @@
return true
}
- moduleName := module.Name()
+ moduleName := moduleNameWithPossibleOverride(ctx, module)
allowlist := ctx.Config().Bp2buildPackageConfig
moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName]
moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[ctx.OtherModuleType(module)]
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 9c273d9..10cf60a 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -18,7 +18,6 @@
"bytes"
"fmt"
"os"
- "os/exec"
"path"
"path/filepath"
"runtime"
@@ -61,6 +60,8 @@
"AUTO_UNINITIALIZE",
"USE_CCACHE",
"LLVM_NEXT",
+ "LLVM_PREBUILTS_VERSION",
+ "LLVM_RELEASE_VERSION",
"ALLOW_UNKNOWN_WARNING_OPTION",
"UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT",
@@ -86,12 +87,10 @@
func mixedBuildsPrepareMutator(ctx BottomUpMutatorContext) {
if m := ctx.Module(); m.Enabled() {
if mixedBuildMod, ok := m.(MixedBuildBuildable); ok {
- queueMixedBuild := mixedBuildMod.IsMixedBuildSupported(ctx) && MixedBuildsEnabled(ctx)
+ mixedBuildEnabled := MixedBuildsEnabled(ctx)
+ queueMixedBuild := mixedBuildMod.IsMixedBuildSupported(ctx) && mixedBuildEnabled == MixedBuildEnabled
if queueMixedBuild {
mixedBuildMod.QueueBazelCall(ctx)
- } else if _, ok := ctx.Config().bazelForceEnabledModules[m.Name()]; ok {
- // TODO(b/273910287) - remove this once --ensure_allowlist_integrity is added
- ctx.ModuleErrorf("Attempted to force enable an unready module: %s. Did you forget to Bp2BuildDefaultTrue its directory?\n", m.Name())
}
}
}
@@ -220,8 +219,7 @@
}
type bazelRunner interface {
- createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) *exec.Cmd
- issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
+ issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
}
type bazelPaths struct {
@@ -660,36 +658,6 @@
expression string
}
-type mockBazelRunner struct {
- bazelCommandResults map[bazelCommand]string
- // use *exec.Cmd as a key to get the bazelCommand, the map will be used in issueBazelCommand()
- // Register createBazelCommand() invocations. Later, an
- // issueBazelCommand() invocation can be mapped to the *exec.Cmd instance
- // and then to the expected result via bazelCommandResults
- tokens map[*exec.Cmd]bazelCommand
- commands []bazelCommand
- extraFlags []string
-}
-
-func (r *mockBazelRunner) createBazelCommand(_ Config, _ *bazelPaths, _ bazel.RunName,
- command bazelCommand, extraFlags ...string) *exec.Cmd {
- r.commands = append(r.commands, command)
- r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
- cmd := &exec.Cmd{}
- if r.tokens == nil {
- r.tokens = make(map[*exec.Cmd]bazelCommand)
- }
- r.tokens[cmd] = command
- return cmd
-}
-
-func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, _ *metrics.EventHandler) (string, string, error) {
- if command, ok := r.tokens[bazelCmd]; ok {
- return r.bazelCommandResults[command], "", nil
- }
- return "", "", nil
-}
-
type builtinBazelRunner struct {
useBazelProxy bool
outDir string
@@ -699,17 +667,12 @@
// Returns (stdout, stderr, error). The first and second return values are strings
// containing the stdout and stderr of the run command, and an error is returned if
// the invocation returned an error code.
-func (r *builtinBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (string, string, error) {
+func (r *builtinBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
if r.useBazelProxy {
eventHandler.Begin("client_proxy")
defer eventHandler.End("client_proxy")
proxyClient := bazel.NewProxyClient(r.outDir)
- // Omit the arg containing the Bazel binary, as that is handled by the proxy
- // server.
- bazelFlags := bazelCmd.Args[1:]
- // TODO(b/270989498): Refactor these functions to not take exec.Cmd, as its
- // not actually executed for client proxying.
- resp, err := proxyClient.IssueCommand(bazel.CmdRequest{bazelFlags, bazelCmd.Env})
+ resp, err := proxyClient.IssueCommand(cmdRequest)
if err != nil {
return "", "", err
@@ -721,33 +684,23 @@
} else {
eventHandler.Begin("bazel command")
defer eventHandler.End("bazel command")
- stderr := &bytes.Buffer{}
- bazelCmd.Stderr = stderr
- if output, err := bazelCmd.Output(); err != nil {
- return "", string(stderr.Bytes()),
- fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
- err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
- } else {
- return string(output), string(stderr.Bytes()), nil
- }
+
+ stdout, stderr, err := bazel.ExecBazel(paths.bazelPath, absolutePath(paths.syntheticWorkspaceDir()), cmdRequest)
+ return string(stdout), string(stderr), err
}
}
-func (r *builtinBazelRunner) createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand,
- extraFlags ...string) *exec.Cmd {
+func (context *mixedBuildBazelContext) createBazelCommand(config Config, runName bazel.RunName, command bazelCommand,
+ extraFlags ...string) bazel.CmdRequest {
cmdFlags := []string{
- "--output_base=" + absolutePath(paths.outputBase),
+ "--output_base=" + absolutePath(context.paths.outputBase),
command.command,
command.expression,
- // TODO(asmundak): is it needed in every build?
- "--profile=" + shared.BazelMetricsFilename(paths, runName),
+ "--profile=" + shared.BazelMetricsFilename(context.paths, runName),
// We don't need to set --host_platforms because it's set in bazelrc files
// that the bazel shell script wrapper passes
- // Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
- "--experimental_repository_disable_download",
-
// Suppress noise
"--ui_event_filters=-INFO",
"--noshow_progress",
@@ -755,15 +708,13 @@
}
cmdFlags = append(cmdFlags, extraFlags...)
- bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
- bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
extraEnv := []string{
- "HOME=" + paths.homeDir,
+ "HOME=" + context.paths.homeDir,
pwdPrefix(),
- "BUILD_DIR=" + absolutePath(paths.soongOutDir),
+ "BUILD_DIR=" + absolutePath(context.paths.soongOutDir),
// Make OUT_DIR absolute here so build/bazel/bin/bazel uses the correct
// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
- "OUT_DIR=" + absolutePath(paths.outDir()),
+ "OUT_DIR=" + absolutePath(context.paths.outDir()),
// Disables local host detection of gcc; toolchain information is defined
// explicitly in BUILD files.
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
@@ -775,15 +726,15 @@
}
extraEnv = append(extraEnv, fmt.Sprintf("%s=%s", envvar, val))
}
- bazelCmd.Env = append(os.Environ(), extraEnv...)
+ envVars := append(os.Environ(), extraEnv...)
- return bazelCmd
+ return bazel.CmdRequest{cmdFlags, envVars}
}
-func printableCqueryCommand(bazelCmd *exec.Cmd) string {
- outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(bazelCmd.Args, "\" \"") + "\""
+func (context *mixedBuildBazelContext) printableCqueryCommand(bazelCmd bazel.CmdRequest) string {
+ args := append([]string{context.paths.bazelPath}, bazelCmd.Argv...)
+ outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(args, "\" \"") + "\""
return outputString
-
}
func (context *mixedBuildBazelContext) mainBzlFileContents() []byte {
@@ -1106,9 +1057,10 @@
const buildrootLabel = "@soong_injection//mixed_builds:buildroot"
var (
- cqueryCmd = bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
- aqueryCmd = bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
- buildCmd = bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
+ cqueryCmd = bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
+ aqueryCmd = bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
+ buildCmd = bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
+ allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
)
// Issues commands to Bazel to receive results for all cquery requests
@@ -1170,12 +1122,12 @@
extraFlags = append(extraFlags, "--collect_code_coverage")
}
- cqueryCommandWithFlag := context.createBazelCommand(config, context.paths, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
- cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag, eventHandler)
+ cqueryCmdRequest := context.createBazelCommand(config, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
+ cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCmdRequest, context.paths, eventHandler)
if cqueryErr != nil {
return cqueryErr
}
- cqueryCommandPrint := fmt.Sprintf("cquery command line:\n %s \n\n\n", printableCqueryCommand(cqueryCommandWithFlag))
+ cqueryCommandPrint := fmt.Sprintf("cquery command line:\n %s \n\n\n", context.printableCqueryCommand(cqueryCmdRequest))
if err := os.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryCommandPrint+cqueryOutput), 0666); err != nil {
return err
}
@@ -1233,8 +1185,8 @@
extraFlags = append(extraFlags, "--instrumentation_filter="+strings.Join(paths, ","))
}
}
- aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
- extraFlags...), eventHandler)
+ aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, bazel.AqueryBuildRootRunName, aqueryCmd,
+ extraFlags...), context.paths, eventHandler)
if err != nil {
return err
}
@@ -1249,7 +1201,7 @@
// Issue a build command of the phony root to generate symlink forests for dependencies of the
// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
// but some of symlinks may be required to resolve source dependencies of the build.
- _, _, err := context.issueBazelCommand(context.createBazelCommand(config, context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd), eventHandler)
+ _, _, err := context.issueBazelCommand(context.createBazelCommand(config, bazel.BazelBuildPhonyRootRunName, buildCmd), context.paths, eventHandler)
return err
}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index c67d7fb..b17b765 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -8,6 +8,7 @@
"strings"
"testing"
+ "android/soong/bazel"
"android/soong/bazel/cquery"
analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
@@ -19,6 +20,34 @@
type testInvokeBazelContext struct{}
+type mockBazelRunner struct {
+ testHelper *testing.T
+ // Stores mock behavior. If an issueBazelCommand request is made for command
+ // k, and {k:v} is present in this map, then the mock will return v.
+ bazelCommandResults map[bazelCommand]string
+ // Requests actually made of the mockBazelRunner with issueBazelCommand,
+ // keyed by the command they represent.
+ bazelCommandRequests map[bazelCommand]bazel.CmdRequest
+}
+
+func (r *mockBazelRunner) bazelCommandForRequest(cmdRequest bazel.CmdRequest) bazelCommand {
+ for _, arg := range cmdRequest.Argv {
+ for _, cmdType := range allBazelCommands {
+ if arg == cmdType.command {
+ return cmdType
+ }
+ }
+ }
+ r.testHelper.Fatalf("Unrecognized bazel request: %s", cmdRequest)
+ return cqueryCmd
+}
+
+func (r *mockBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
+ command := r.bazelCommandForRequest(cmdRequest)
+ r.bazelCommandRequests[command] = cmdRequest
+ return r.bazelCommandResults[command], "", nil
+}
+
func (t *testInvokeBazelContext) GetEventHandler() *metrics.EventHandler {
return &metrics.EventHandler{}
}
@@ -36,9 +65,7 @@
`@//foo:foo|arm64_armv8-a|android|within_apex|29>>out/foo/foo.txt`,
`@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
}
- bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: strings.Join(cmd_results, "\n"),
- })
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{cqueryCmd: strings.Join(cmd_results, "\n")})
bazelContext.QueueBazelRequest(label_foo, cquery.GetOutputFiles, cfg_foo)
bazelContext.QueueBazelRequest(label_bar, cquery.GetOutputFiles, cfg_bar)
@@ -139,8 +166,7 @@
if err != nil {
t.Error(err)
}
- bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
- bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: string(data)})
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)})
err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
if err != nil {
@@ -166,30 +192,26 @@
testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,+foo2,-bar1,-bar2`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,+foo2,-bar1,-bar2")
testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,-bar1`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,-bar1")
testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
testConfig.productVariables.NativeCoverageExcludePaths = nil
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1")
testConfig.productVariables.NativeCoveragePaths = nil
testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=-bar1`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=-bar1")
testConfig.productVariables.NativeCoveragePaths = []string{"*"}
testConfig.productVariables.NativeCoverageExcludePaths = nil
- verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+.*`)
+ verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+.*")
testConfig.productVariables.ClangCoverage = boolPtr(false)
- actual := verifyExtraFlags(t, testConfig, ``)
- if strings.Contains(actual, "--collect_code_coverage") ||
- strings.Contains(actual, "--instrumentation_filter=") {
- t.Errorf("Expected code coverage disabled, but got %#v", actual)
- }
+ verifyAqueryDoesNotContainSubstrings(t, testConfig, "collect_code_coverage", "instrumentation_filter")
}
func TestBazelRequestsSorted(t *testing.T) {
@@ -268,7 +290,8 @@
}
}
-func verifyExtraFlags(t *testing.T, config Config, expected string) string {
+func verifyAqueryContainsFlags(t *testing.T, config Config, expected ...string) {
+ t.Helper()
bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
@@ -276,17 +299,49 @@
t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
- flags := bazelContext.bazelRunner.(*mockBazelRunner).extraFlags
- if expected := 3; len(flags) != expected {
- t.Errorf("Expected %d extra flags got %#v", expected, flags)
+ sliceContains := func(slice []string, x string) bool {
+ for _, s := range slice {
+ if s == x {
+ return true
+ }
+ }
+ return false
}
- actual := flags[1]
- if !strings.Contains(actual, expected) {
- t.Errorf("Expected %#v got %#v", expected, actual)
+ aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
+
+ for _, expectedFlag := range expected {
+ if !sliceContains(aqueryArgv, expectedFlag) {
+ t.Errorf("aquery does not contain expected flag %#v. Argv was: %#v", expectedFlag, aqueryArgv)
+ }
+ }
+}
+
+func verifyAqueryDoesNotContainSubstrings(t *testing.T, config Config, substrings ...string) {
+ t.Helper()
+ bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
+
+ err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
+ if err != nil {
+ t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
}
- return actual
+ sliceContainsSubstring := func(slice []string, substring string) bool {
+ for _, s := range slice {
+ if strings.Contains(s, substring) {
+ return true
+ }
+ }
+ return false
+ }
+
+ aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
+
+ for _, substring := range substrings {
+ if sliceContainsSubstring(aqueryArgv, substring) {
+ t.Errorf("aquery contains unexpected substring %#v. Argv was: %#v", substring, aqueryArgv)
+ }
+ }
}
func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*mixedBuildBazelContext, string) {
@@ -296,11 +351,14 @@
outputBase: "outputbase",
workspaceDir: "workspace_dir",
}
- aqueryCommand := bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}
- if _, exists := bazelCommandResults[aqueryCommand]; !exists {
- bazelCommandResults[aqueryCommand] = ""
+ if _, exists := bazelCommandResults[aqueryCmd]; !exists {
+ bazelCommandResults[aqueryCmd] = ""
}
- runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults}
+ runner := &mockBazelRunner{
+ testHelper: t,
+ bazelCommandResults: bazelCommandResults,
+ bazelCommandRequests: map[bazelCommand]bazel.CmdRequest{},
+ }
return &mixedBuildBazelContext{
bazelRunner: runner,
paths: &p,
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index bad7baf..ddbdbd4 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -453,8 +453,8 @@
}
func bp2buildModuleLabel(ctx BazelConversionContext, module blueprint.Module) string {
- moduleName := ctx.OtherModuleName(module)
- moduleDir := ctx.OtherModuleDir(module)
+ moduleName := moduleNameWithPossibleOverride(ctx, module)
+ moduleDir := moduleDirWithPossibleOverride(ctx, module)
if moduleDir == Bp2BuildTopLevel {
moduleDir = ""
}
diff --git a/android/bazel_test.go b/android/bazel_test.go
index 87b2c8f..77e2515 100644
--- a/android/bazel_test.go
+++ b/android/bazel_test.go
@@ -218,7 +218,7 @@
var bazelableBazelModuleBase = BazelModuleBase{
bazelProperties: properties{
- Bazel_module: bazelModuleProperties{
+ Bazel_module: BazelModuleProperties{
CanConvertToBazel: true,
},
},
@@ -344,7 +344,7 @@
},
BazelModuleBase: BazelModuleBase{
bazelProperties: properties{
- Bazel_module: bazelModuleProperties{
+ Bazel_module: BazelModuleProperties{
CanConvertToBazel: true,
Bp2build_available: proptools.BoolPtr(true),
},
diff --git a/android/config.go b/android/config.go
index 980460a..01b8cfa 100644
--- a/android/config.go
+++ b/android/config.go
@@ -102,6 +102,8 @@
UseBazelProxy bool
BuildFromTextStub bool
+
+ EnsureAllowlistIntegrity bool
}
// Build modes that soong_build can run as.
@@ -181,6 +183,16 @@
return String(c.config.productVariables.DeviceMaxPageSizeSupported)
}
+// The release version passed to aconfig, derived from RELEASE_VERSION
+func (c Config) ReleaseVersion() string {
+ return c.config.productVariables.ReleaseVersion
+}
+
+// The flag values files passed to aconfig, derived from RELEASE_VERSION
+func (c Config) ReleaseDeviceConfigValueSets() []string {
+ return c.config.productVariables.ReleaseDeviceConfigValueSets
+}
+
// A DeviceConfig object represents the configuration for a particular device
// being built. For now there will only be one of these, but in the future there
// may be multiple devices being built.
@@ -285,6 +297,11 @@
// If buildFromTextStub is true then the Java API stubs are
// built from the signature text files, not the source Java files.
buildFromTextStub bool
+
+ // If ensureAllowlistIntegrity is true, then the presence of any allowlisted
+ // modules that aren't mixed-built for at least one variant will cause a build
+ // failure
+ ensureAllowlistIntegrity bool
}
type deviceConfig struct {
@@ -599,7 +616,7 @@
setBazelMode(cmdArgs.BazelMode, "--bazel-mode", BazelProdMode)
setBazelMode(cmdArgs.BazelModeStaging, "--bazel-mode-staging", BazelStagingMode)
- for _, module := range strings.Split(cmdArgs.BazelForceEnabledModules, ",") {
+ for _, module := range getForceEnabledModulesFromFlag(cmdArgs.BazelForceEnabledModules) {
config.bazelForceEnabledModules[module] = struct{}{}
}
config.BazelContext, err = NewBazelContext(config)
@@ -608,6 +625,13 @@
return Config{config}, err
}
+func getForceEnabledModulesFromFlag(forceEnabledFlag string) []string {
+ if forceEnabledFlag == "" {
+ return []string{}
+ }
+ return strings.Split(forceEnabledFlag, ",")
+}
+
// mockFileSystem replaces all reads with accesses to the provided map of
// filenames to contents stored as a byte slice.
func (c *config) mockFileSystem(bp string, fs map[string][]byte) {
@@ -1826,6 +1850,10 @@
return uncheckedFinalApiLevel(apiLevel)
}
+func (c *deviceConfig) BuildBrokenPluginValidation() []string {
+ return c.config.productVariables.BuildBrokenPluginValidation
+}
+
func (c *deviceConfig) BuildBrokenClangAsFlags() bool {
return c.config.productVariables.BuildBrokenClangAsFlags
}
@@ -1918,6 +1946,14 @@
return Bool(c.productVariables.HostMusl)
}
+func (c *config) GetMixedBuildsEnabledModules() map[string]struct{} {
+ return c.mixedBuildEnabledModules
+}
+
+func (c *config) GetMixedBuildsDisabledModules() map[string]struct{} {
+ return c.mixedBuildDisabledModules
+}
+
func (c *config) LogMixedBuild(ctx BaseModuleContext, useBazel bool) {
moduleName := ctx.Module().Name()
c.mixedBuildsLock.Lock()
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
index 830890d..2beeb51 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -95,15 +95,6 @@
return ev.pctx.VariableConfigMethod(name, method)
}
-func (ev ExportedVariables) ExportStringStaticVariableWithEnvOverride(name, envVar, defaultVal string) {
- ev.ExportVariableConfigMethod(name, func(config Config) string {
- if override := config.Getenv(envVar); override != "" {
- return override
- }
- return defaultVal
- })
-}
-
// ExportSourcePathVariable declares a static "source path" variable and exports
// it to Bazel's toolchain.
func (ev ExportedVariables) ExportSourcePathVariable(name string, value string) {
diff --git a/android/deptag.go b/android/deptag.go
index be5c35c..a15443b 100644
--- a/android/deptag.go
+++ b/android/deptag.go
@@ -34,10 +34,10 @@
var _ InstallNeededDependencyTag = InstallAlwaysNeededDependencyTag{}
-// IsInstallDepNeeded returns true if the dependency tag implements the InstallNeededDependencyTag
+// IsInstallDepNeededTag returns true if the dependency tag implements the InstallNeededDependencyTag
// interface and the InstallDepNeeded returns true, meaning that the installed files of the parent
// should depend on the installed files of the child.
-func IsInstallDepNeeded(tag blueprint.DependencyTag) bool {
+func IsInstallDepNeededTag(tag blueprint.DependencyTag) bool {
if i, ok := tag.(InstallNeededDependencyTag); ok {
return i.InstallDepNeeded()
}
diff --git a/android/filegroup.go b/android/filegroup.go
index 0ca5dc5..f30ee51 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -75,7 +75,8 @@
// https://docs.bazel.build/versions/master/be/general.html#filegroup
type bazelFilegroupAttributes struct {
- Srcs bazel.LabelListAttribute
+ Srcs bazel.LabelListAttribute
+ Applicable_licenses bazel.LabelListAttribute
}
type bazelAidlLibraryAttributes struct {
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 18b63d3..73000a9 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -74,7 +74,7 @@
if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
- if isContainer || IsInstallDepNeeded(ctx.OtherModuleDependencyTag(dep)) {
+ if isContainer || isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
allDepMetadataDepSets = append(allDepMetadataDepSets, info.LicenseMetadataDepSet)
}
diff --git a/android/makefile_goal.go b/android/makefile_goal.go
deleted file mode 100644
index 07354a6..0000000
--- a/android/makefile_goal.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2020 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 (
- "fmt"
- "io"
- "path/filepath"
-
- "github.com/google/blueprint/proptools"
-)
-
-func init() {
- RegisterModuleType("makefile_goal", MakefileGoalFactory)
-}
-
-type makefileGoalProperties struct {
- // Sources.
-
- // Makefile goal output file path, relative to PRODUCT_OUT.
- Product_out_path *string
-}
-
-type makefileGoal struct {
- ModuleBase
-
- properties makefileGoalProperties
-
- // Destination. Output file path of this module.
- outputFilePath OutputPath
-}
-
-var _ AndroidMkEntriesProvider = (*makefileGoal)(nil)
-var _ OutputFileProducer = (*makefileGoal)(nil)
-
-// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles.
-func (p *makefileGoal) inputPath() *string {
- if p.properties.Product_out_path != nil {
- return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path)))
- }
- return nil
-}
-
-// OutputFileProducer
-func (p *makefileGoal) OutputFiles(tag string) (Paths, error) {
- if tag != "" {
- return nil, fmt.Errorf("unsupported tag %q", tag)
- }
- return Paths{p.outputFilePath}, nil
-}
-
-// AndroidMkEntriesProvider
-func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) {
- if p.inputPath() == nil {
- ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required")
- }
-}
-
-func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) {
- filename := filepath.Base(proptools.String(p.inputPath()))
- p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
-
- ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath)
-}
-
-func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries {
- return []AndroidMkEntries{AndroidMkEntries{
- Class: "ETC",
- OutputFile: OptionalPathForPath(p.outputFilePath),
- ExtraFooters: []AndroidMkExtraFootersFunc{
- func(w io.Writer, name, prefix, moduleDir string) {
- // Can't use Cp because inputPath() is not a valid Path.
- fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath)
- },
- },
- }}
-}
-
-// Import a Makefile goal to Soong by copying the file built by
-// the goal to a path visible to Soong. This rule only works on boot images.
-func MakefileGoalFactory() Module {
- module := &makefileGoal{}
- module.AddProperties(&module.properties)
- InitAndroidModule(module)
- return module
-}
diff --git a/android/module.go b/android/module.go
index ba47453..db602a0 100644
--- a/android/module.go
+++ b/android/module.go
@@ -925,6 +925,12 @@
// and don't create a rule to install the file.
SkipInstall bool `blueprint:"mutated"`
+ // UninstallableApexPlatformVariant is set by MakeUninstallable called by the apex
+ // mutator. MakeUninstallable also sets HideFromMake. UninstallableApexPlatformVariant
+ // is used to avoid adding install or packaging dependencies into libraries provided
+ // by apexes.
+ UninstallableApexPlatformVariant bool `blueprint:"mutated"`
+
// Whether the module has been replaced by a prebuilt
ReplacedByPrebuilt bool `blueprint:"mutated"`
@@ -2009,6 +2015,7 @@
// have other side effects, in particular when it adds a NOTICE file target,
// which other install targets might depend on.
func (m *ModuleBase) MakeUninstallable() {
+ m.commonProperties.UninstallableApexPlatformVariant = true
m.HideFromMake()
}
@@ -2038,13 +2045,19 @@
}
// computeInstallDeps finds the installed paths of all dependencies that have a dependency
-// tag that is annotated as needing installation via the IsInstallDepNeeded method.
+// tag that is annotated as needing installation via the isInstallDepNeeded method.
func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]*installPathsDepSet, []*packagingSpecsDepSet) {
var installDeps []*installPathsDepSet
var packagingSpecs []*packagingSpecsDepSet
ctx.VisitDirectDeps(func(dep Module) {
- if IsInstallDepNeeded(ctx.OtherModuleDependencyTag(dep)) && !dep.IsHideFromMake() && !dep.IsSkipInstall() {
- installDeps = append(installDeps, dep.base().installFilesDepSet)
+ if isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
+ // Installation is still handled by Make, so anything hidden from Make is not
+ // installable.
+ if !dep.IsHideFromMake() && !dep.IsSkipInstall() {
+ installDeps = append(installDeps, dep.base().installFilesDepSet)
+ }
+ // Add packaging deps even when the dependency is not installed so that uninstallable
+ // modules can still be packaged. Often the package will be installed instead.
packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
}
})
@@ -2052,6 +2065,17 @@
return installDeps, packagingSpecs
}
+// isInstallDepNeeded returns true if installing the output files of the current module
+// should also install the output files of the given dependency and dependency tag.
+func isInstallDepNeeded(dep Module, tag blueprint.DependencyTag) bool {
+ // Don't add a dependency from the platform to a library provided by an apex.
+ if dep.base().commonProperties.UninstallableApexPlatformVariant {
+ return false
+ }
+ // Only install modules if the dependency tag is an InstallDepNeeded tag.
+ return IsInstallDepNeededTag(tag)
+}
+
func (m *ModuleBase) FilesToInstall() InstallPaths {
return m.installFiles
}
@@ -2438,7 +2462,7 @@
func (m *ModuleBase) isHandledByBazel(ctx ModuleContext) (MixedBuildBuildable, bool) {
if mixedBuildMod, ok := m.module.(MixedBuildBuildable); ok {
- if mixedBuildMod.IsMixedBuildSupported(ctx) && MixedBuildsEnabled(ctx) {
+ if mixedBuildMod.IsMixedBuildSupported(ctx) && (MixedBuildsEnabled(ctx) == MixedBuildEnabled) {
return mixedBuildMod, true
}
}
diff --git a/android/mutator.go b/android/mutator.go
index 4ec9604..0a091eb 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -273,6 +273,12 @@
// This function can be used to create alias definitions in a directory that is different
// from the directory of the visited Soong module.
CreateBazelTargetAliasInDir(dir string, name string, actual bazel.Label)
+
+ // CreateBazelConfigSetting creates a config_setting in <dir>/BUILD.bazel
+ // build/bazel has several static config_setting(s) that are used in Bazel builds.
+ // This function can be used to createa additional config_setting(s) based on the build graph
+ // (e.g. a config_setting specific to an apex variant)
+ CreateBazelConfigSetting(csa bazel.ConfigSettingAttributes, ca CommonAttributes, dir string)
}
type topDownMutatorContext struct {
@@ -738,6 +744,23 @@
mod.base().addBp2buildInfo(info)
}
+func (t *topDownMutatorContext) CreateBazelConfigSetting(
+ csa bazel.ConfigSettingAttributes,
+ ca CommonAttributes,
+ dir string) {
+ mod := t.Module()
+ info := bp2buildInfo{
+ Dir: dir,
+ BazelProps: bazel.BazelTargetModuleProperties{
+ Rule_class: "config_setting",
+ },
+ CommonAttrs: ca,
+ ConstraintAttrs: constraintAttributes{},
+ Attrs: &csa,
+ }
+ mod.base().addBp2buildInfo(info)
+}
+
// ApexAvailableTags converts the apex_available property value of an ApexModule
// module and returns it as a list of keyed tags.
func ApexAvailableTags(mod Module) bazel.StringListAttribute {
@@ -758,6 +781,35 @@
return attr
}
+func ApexAvailableTagsWithoutTestApexes(ctx BaseModuleContext, mod Module) bazel.StringListAttribute {
+ attr := bazel.StringListAttribute{}
+ if am, ok := mod.(ApexModule); ok {
+ apexAvailableWithoutTestApexes := removeTestApexes(ctx, am.apexModuleBase().ApexAvailable())
+ // If a user does not specify apex_available in Android.bp, then soong provides a default.
+ // To avoid verbosity of BUILD files, remove this default from user-facing BUILD files.
+ if len(am.apexModuleBase().ApexProperties.Apex_available) == 0 {
+ apexAvailableWithoutTestApexes = []string{}
+ }
+ attr.Value = ConvertApexAvailableToTags(apexAvailableWithoutTestApexes)
+ }
+ return attr
+}
+
+func removeTestApexes(ctx BaseModuleContext, apex_available []string) []string {
+ testApexes := []string{}
+ for _, aa := range apex_available {
+ // ignore the wildcards
+ if InList(aa, AvailableToRecognziedWildcards) {
+ continue
+ }
+ mod, _ := ctx.ModuleFromName(aa)
+ if apex, ok := mod.(ApexTestInterface); ok && apex.IsTestApex() {
+ testApexes = append(testApexes, aa)
+ }
+ }
+ return RemoveListFromList(CopyOf(apex_available), testApexes)
+}
+
func ConvertApexAvailableToTags(apexAvailable []string) []string {
if len(apexAvailable) == 0 {
// We need nil specifically to make bp2build not add the tags property at all,
@@ -771,6 +823,13 @@
return result
}
+// ConvertApexAvailableToTagsWithoutTestApexes converts a list of apex names to a list of bazel tags
+// This function drops any test apexes from the input.
+func ConvertApexAvailableToTagsWithoutTestApexes(ctx BaseModuleContext, apexAvailable []string) []string {
+ noTestApexes := removeTestApexes(ctx, apexAvailable)
+ return ConvertApexAvailableToTags(noTestApexes)
+}
+
func (t *topDownMutatorContext) createBazelTargetModule(
bazelProps bazel.BazelTargetModuleProperties,
commonAttrs CommonAttributes,
diff --git a/android/neverallow.go b/android/neverallow.go
index 2139c3c..5b5e613 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -55,7 +55,6 @@
AddNeverAllowRules(createJavaDeviceForHostRules()...)
AddNeverAllowRules(createCcSdkVariantRules()...)
AddNeverAllowRules(createUncompressDexRules()...)
- AddNeverAllowRules(createMakefileGoalRules()...)
AddNeverAllowRules(createInitFirstStageRules()...)
AddNeverAllowRules(createProhibitFrameworkAccessRules()...)
AddNeverAllowRules(createBp2BuildRule())
@@ -236,20 +235,6 @@
}
}
-func createMakefileGoalRules() []Rule {
- allowlist := []string{
- // libwifi_hal uses makefile_goal for its dependencies
- "frameworks/opt/net/wifi/libwifi_hal",
- }
- return []Rule{
- NeverAllow().
- ModuleType("makefile_goal").
- WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
- NotIn(allowlist...).
- Because("Only boot images may be imported as a makefile goal if not in allowed projects"),
- }
-}
-
func createInitFirstStageRules() []Rule {
return []Rule{
NeverAllow().
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 5f5f9a1..ddd982d 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -313,45 +313,6 @@
"module \"outside_art_libraries\": violates neverallow",
},
},
- {
- name: "disallowed makefile_goal",
- fs: map[string][]byte{
- "Android.bp": []byte(`
- makefile_goal {
- name: "foo",
- product_out_path: "boot/trap.img"
- }
- `),
- },
- expectedErrors: []string{
- "Only boot images.* may be imported as a makefile goal",
- },
- },
- {
- name: "disallowed makefile_goal outside external",
- fs: map[string][]byte{
- "project/Android.bp": []byte(`
- makefile_goal {
- name: "foo",
- product_out_path: "obj/EXE/foo",
- }
- `),
- },
- expectedErrors: []string{
- "not in allowed projects",
- },
- },
- {
- name: "allow makefile_goal within external",
- fs: map[string][]byte{
- "frameworks/opt/net/wifi/libwifi_hal/Android.bp": []byte(`
- makefile_goal {
- name: "foo",
- product_out_path: "obj/EXE/foo",
- }
- `),
- },
- },
// Tests for the rule prohibiting the use of framework
{
name: "prohibit framework",
@@ -391,7 +352,6 @@
ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
- ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule)
}),
)
@@ -489,22 +449,3 @@
func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
-
-type mockMakefileGoalProperties struct {
- Product_out_path *string
-}
-
-type mockMakefileGoalModule struct {
- ModuleBase
- properties mockMakefileGoalProperties
-}
-
-func newMockMakefileGoalModule() Module {
- m := &mockMakefileGoalModule{}
- m.AddProperties(&m.properties)
- InitAndroidModule(m)
- return m
-}
-
-func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) {
-}
diff --git a/android/ninja_deps.go b/android/ninja_deps.go
index 2f442d5..1d50a47 100644
--- a/android/ninja_deps.go
+++ b/android/ninja_deps.go
@@ -14,7 +14,10 @@
package android
-import "sort"
+import (
+ "android/soong/starlark_import"
+ "sort"
+)
func (c *config) addNinjaFileDeps(deps ...string) {
for _, dep := range deps {
@@ -40,4 +43,11 @@
func (ninjaDepsSingleton) GenerateBuildActions(ctx SingletonContext) {
ctx.AddNinjaFileDeps(ctx.Config().ninjaFileDeps()...)
+
+ deps, err := starlark_import.GetNinjaDeps()
+ if err != nil {
+ ctx.Errorf("Error running starlark code: %s", err)
+ } else {
+ ctx.AddNinjaFileDeps(deps...)
+ }
}
diff --git a/android/override_module.go b/android/override_module.go
index 2d30a85..a4b7431 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -28,7 +28,6 @@
// module based on it.
import (
- "fmt"
"sort"
"sync"
@@ -47,8 +46,8 @@
// Internal funcs to handle interoperability between override modules and prebuilts.
// i.e. cases where an overriding module, too, is overridden by a prebuilt module.
- setOverriddenByPrebuilt(overridden bool)
- getOverriddenByPrebuilt() bool
+ setOverriddenByPrebuilt(prebuilt Module)
+ getOverriddenByPrebuilt() Module
// Directory containing the Blueprint definition of the overriding module
setModuleDir(string)
@@ -61,7 +60,7 @@
overridingProperties []interface{}
- overriddenByPrebuilt bool
+ overriddenByPrebuilt Module
moduleDir string
}
@@ -97,11 +96,11 @@
return proptools.String(o.moduleProperties.Base)
}
-func (o *OverrideModuleBase) setOverriddenByPrebuilt(overridden bool) {
- o.overriddenByPrebuilt = overridden
+func (o *OverrideModuleBase) setOverriddenByPrebuilt(prebuilt Module) {
+ o.overriddenByPrebuilt = prebuilt
}
-func (o *OverrideModuleBase) getOverriddenByPrebuilt() bool {
+func (o *OverrideModuleBase) getOverriddenByPrebuilt() Module {
return o.overriddenByPrebuilt
}
@@ -121,7 +120,7 @@
addOverride(o OverrideModule)
getOverrides() []OverrideModule
- override(ctx BaseModuleContext, o OverrideModule)
+ override(ctx BaseModuleContext, m Module, o OverrideModule)
GetOverriddenBy() string
GetOverriddenByModuleDir() string
@@ -192,7 +191,8 @@
}
// Overrides a base module with the given OverrideModule.
-func (b *OverridableModuleBase) override(ctx BaseModuleContext, o OverrideModule) {
+func (b *OverridableModuleBase) override(ctx BaseModuleContext, m Module, o OverrideModule) {
+
for _, p := range b.overridableProperties {
for _, op := range o.getOverridingProperties() {
if proptools.TypeEqual(p, op) {
@@ -214,6 +214,17 @@
}
b.overridableModuleProperties.OverriddenBy = o.Name()
b.overridableModuleProperties.OverriddenByModuleDir = o.ModuleDir()
+
+ if oBazelable, ok := o.base().module.(Bazelable); ok {
+ if bBazelable, ok := m.(Bazelable); ok {
+ oProps := oBazelable.bazelProps()
+ bProps := bBazelable.bazelProps()
+ bProps.Bazel_module.Bp2build_available = oProps.Bazel_module.Bp2build_available
+ bProps.Bazel_module.Label = oProps.Bazel_module.Label
+ } else {
+ ctx.ModuleErrorf("Override type cannot be Bazelable if original module type is not Bazelable %v %v.", o.Name(), m.Name())
+ }
+ }
}
// GetOverriddenBy returns the name of the override module that has overridden this module.
@@ -270,7 +281,7 @@
panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name())
}
if prebuilt.UsePrebuilt() {
- module.setOverriddenByPrebuilt(true)
+ module.setOverriddenByPrebuilt(dep)
return
}
})
@@ -302,10 +313,13 @@
// is specified.
ctx.AliasVariation(variants[0])
for i, o := range overrides {
- mods[i+1].(OverridableModule).override(ctx, o)
- if o.getOverriddenByPrebuilt() {
- // The overriding module itself, too, is overridden by a prebuilt. Skip its installation.
- mods[i+1].HideFromMake()
+ mods[i+1].(OverridableModule).override(ctx, mods[i+1], o)
+ if prebuilt := o.getOverriddenByPrebuilt(); prebuilt != nil {
+ // The overriding module itself, too, is overridden by a prebuilt.
+ // Perform the same check for replacement
+ checkInvariantsForSourceAndPrebuilt(ctx, mods[i+1], prebuilt)
+ // Copy the flag and hide it in make
+ mods[i+1].ReplacedByPrebuilt()
}
}
} else if o, ok := ctx.Module().(OverrideModule); ok {
@@ -339,34 +353,26 @@
// variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule
// or if this variant is not overridden.
func ModuleNameWithPossibleOverride(ctx BazelConversionContext) string {
- if overridable, ok := ctx.Module().(OverridableModule); ok {
+ return moduleNameWithPossibleOverride(ctx, ctx.Module())
+}
+
+func moduleNameWithPossibleOverride(ctx bazelOtherModuleContext, module blueprint.Module) string {
+ if overridable, ok := module.(OverridableModule); ok {
if o := overridable.GetOverriddenBy(); o != "" {
return o
}
}
- return ctx.OtherModuleName(ctx.Module())
+ return ctx.OtherModuleName(module)
}
-// ModuleDirWithPossibleOverride returns the dir of the OverrideModule that overrides the current
-// variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule
-// or if this variant is not overridden.
-func moduleDirWithPossibleOverride(ctx BazelConversionContext) string {
- if overridable, ok := ctx.Module().(OverridableModule); ok {
+// moduleDirWithPossibleOverride returns the dir of the OverrideModule that overrides the current
+// variant of the given OverridableModule, or ctx.OtherModuleName() if the module is not an
+// OverridableModule or if the variant is not overridden.
+func moduleDirWithPossibleOverride(ctx bazelOtherModuleContext, module blueprint.Module) string {
+ if overridable, ok := module.(OverridableModule); ok {
if o := overridable.GetOverriddenByModuleDir(); o != "" {
return o
}
}
- return ctx.OtherModuleDir(ctx.Module())
-}
-
-// MaybeBp2buildLabelOfOverridingModule returns the bazel label of the
-// overriding module of an OverridableModule (e.g. override_apex label of a base
-// apex), or the module's label itself if not overridden.
-func MaybeBp2buildLabelOfOverridingModule(ctx BazelConversionContext) string {
- moduleName := ModuleNameWithPossibleOverride(ctx)
- moduleDir := moduleDirWithPossibleOverride(ctx)
- if moduleDir == Bp2BuildTopLevel {
- moduleDir = ""
- }
- return fmt.Sprintf("//%s:%s", moduleDir, moduleName)
+ return ctx.OtherModuleDir(module)
}
diff --git a/android/package.go b/android/package.go
index 2bf6521..7fbc700 100644
--- a/android/package.go
+++ b/android/package.go
@@ -15,6 +15,8 @@
package android
import (
+ "path/filepath"
+
"android/soong/bazel"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -39,8 +41,8 @@
}
type bazelPackageAttributes struct {
- Default_visibility []string
- Default_applicable_licenses bazel.LabelListAttribute
+ Default_visibility []string
+ Default_package_metadata bazel.LabelListAttribute
}
type packageModule struct {
@@ -53,13 +55,32 @@
var _ Bazelable = &packageModule{}
func (p *packageModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
+ defaultPackageMetadata := bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, p.properties.Default_applicable_licenses))
+ // If METADATA file exists in the package, add it to package(default_package_metadata=) using a
+ // filegroup(name="default_metadata_file") which can be accessed later on each module in Bazel
+ // using attribute "applicable_licenses".
+ // Attribute applicable_licenses of filegroup "default_metadata_file" has to be set to [],
+ // otherwise Bazel reports cyclic reference error.
+ if existed, _, _ := ctx.Config().fs.Exists(filepath.Join(ctx.ModuleDir(), "METADATA")); existed {
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "filegroup",
+ },
+ CommonAttributes{Name: "default_metadata_file"},
+ &bazelFilegroupAttributes{
+ Srcs: bazel.MakeLabelListAttribute(BazelLabelForModuleSrc(ctx, []string{"METADATA"})),
+ Applicable_licenses: bazel.LabelListAttribute{Value: bazel.LabelList{Includes: []bazel.Label{}}, EmitEmptyList: true},
+ })
+ defaultPackageMetadata.Value.Add(&bazel.Label{Label: ":default_metadata_file"})
+ }
+
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: "package",
},
CommonAttributes{},
&bazelPackageAttributes{
- Default_applicable_licenses: bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, p.properties.Default_applicable_licenses)),
+ Default_package_metadata: defaultPackageMetadata,
// FIXME(asmundak): once b/221436821 is resolved
Default_visibility: []string{"//visibility:public"},
})
diff --git a/android/packaging_test.go b/android/packaging_test.go
index 91ac1f3..3833437 100644
--- a/android/packaging_test.go
+++ b/android/packaging_test.go
@@ -373,7 +373,7 @@
func TestPackagingWithSkipInstallDeps(t *testing.T) {
// package -[dep]-> foo -[dep]-> bar -[dep]-> baz
- // OK SKIPPED
+ // Packaging should continue transitively through modules that are not installed.
multiTarget := false
runPackagingTest(t, multiTarget,
`
@@ -396,5 +396,5 @@
name: "package",
deps: ["foo"],
}
- `, []string{"lib64/foo"})
+ `, []string{"lib64/foo", "lib64/bar", "lib64/baz"})
}
diff --git a/android/plugin.go b/android/plugin.go
new file mode 100644
index 0000000..c9d1338
--- /dev/null
+++ b/android/plugin.go
@@ -0,0 +1,140 @@
+// Copyright 2022 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 (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "github.com/google/blueprint"
+)
+
+func init() {
+ RegisterPluginSingletonBuildComponents(InitRegistrationContext)
+}
+
+func RegisterPluginSingletonBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterSingletonType("plugins", pluginSingletonFactory)
+}
+
+// pluginSingleton is a singleton to handle allowlisting of the final Android-<product_name>.mk file
+// output.
+func pluginSingletonFactory() Singleton {
+ return &pluginSingleton{}
+}
+
+type pluginSingleton struct{}
+
+var allowedPluginsByName = map[string]bool{
+ "aidl-soong-rules": true,
+ "arm_compute_library_nn_driver": true,
+ "cuttlefish-soong-rules": true,
+ "gki-soong-rules": true,
+ "hidl-soong-rules": true,
+ "kernel-config-soong-rules": true,
+ "soong-angle-codegen": true,
+ "soong-api": true,
+ "soong-art": true,
+ "soong-ca-certificates": true,
+ "soong-ca-certificates-apex": true,
+ "soong-clang": true,
+ "soong-clang-prebuilts": true,
+ "soong-csuite": true,
+ "soong-fluoride": true,
+ "soong-fs_config": true,
+ "soong-icu": true,
+ "soong-java-config-error_prone": true,
+ "soong-libchrome": true,
+ "soong-llvm": true,
+ "soong-robolectric": true,
+ "soong-rust-prebuilts": true,
+ "soong-selinux": true,
+ "soong-wayland-protocol-codegen": true,
+ "treble_report_app": true,
+ "treble_report_local": true,
+ "treble_report_module": true,
+ "vintf-compatibility-matrix-soong-rules": true,
+ "xsdc-soong-rules": true,
+}
+
+const (
+ internalPluginsPath = "vendor/google/build/soong/internal_plugins.json"
+)
+
+type pluginProvider interface {
+ IsPluginFor(string) bool
+}
+
+func maybeAddInternalPluginsToAllowlist(ctx SingletonContext) {
+ if path := ExistentPathForSource(ctx, internalPluginsPath); path.Valid() {
+ ctx.AddNinjaFileDeps(path.String())
+ absPath := absolutePath(path.String())
+ var moreAllowed map[string]bool
+ data, err := ioutil.ReadFile(absPath)
+ if err != nil {
+ ctx.Errorf("Failed to open internal plugins path %q %q", internalPluginsPath, err)
+ }
+ if err := json.Unmarshal(data, &moreAllowed); err != nil {
+ fmt.Fprintf(os.Stderr, "Internal plugins file %q did not parse correctly: %q", data, err)
+ }
+ for k, v := range moreAllowed {
+ allowedPluginsByName[k] = v
+ }
+ }
+}
+
+func (p *pluginSingleton) GenerateBuildActions(ctx SingletonContext) {
+ for _, p := range ctx.DeviceConfig().BuildBrokenPluginValidation() {
+ allowedPluginsByName[p] = true
+ }
+ maybeAddInternalPluginsToAllowlist(ctx)
+
+ disallowedPlugins := map[string]bool{}
+ ctx.VisitAllModulesBlueprint(func(module blueprint.Module) {
+ if ctx.ModuleType(module) != "bootstrap_go_package" {
+ return
+ }
+
+ p, ok := module.(pluginProvider)
+ if !ok || !p.IsPluginFor("soong_build") {
+ return
+ }
+
+ name := ctx.ModuleName(module)
+ if _, ok := allowedPluginsByName[name]; ok {
+ return
+ }
+
+ dir := ctx.ModuleDir(module)
+
+ // allow use of plugins within Soong to not allowlist everything
+ if strings.HasPrefix(dir, "build/soong") {
+ return
+ }
+
+ // allow third party users outside of external to create new plugins, i.e. non-google paths
+ // under vendor or hardware
+ if !strings.HasPrefix(dir, "external/") && IsThirdPartyPath(dir) {
+ return
+ }
+ disallowedPlugins[name] = true
+ })
+ if len(disallowedPlugins) > 0 {
+ ctx.Errorf("New plugins are not supported; however %q were found. Please reach out to the build team or use BUILD_BROKEN_PLUGIN_VALIDATION (see Changes.md for more info).", SortedStringKeys(disallowedPlugins))
+ }
+}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 9b5c0e9..95b772d 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -419,6 +419,20 @@
}
}
+// checkInvariantsForSourceAndPrebuilt checks if invariants are kept when replacing
+// source with prebuilt. Note that the current module for the context is the source module.
+func checkInvariantsForSourceAndPrebuilt(ctx BaseModuleContext, s, p Module) {
+ if _, ok := s.(OverrideModule); ok {
+ // skip the check when the source module is `override_X` because it's only a placeholder
+ // for the actual source module. The check will be invoked for the actual module.
+ return
+ }
+ if sourcePartition, prebuiltPartition := s.PartitionTag(ctx.DeviceConfig()), p.PartitionTag(ctx.DeviceConfig()); sourcePartition != prebuiltPartition {
+ ctx.OtherModuleErrorf(p, "partition is different: %s(%s) != %s(%s)",
+ sourcePartition, ctx.ModuleName(), prebuiltPartition, ctx.OtherModuleName(p))
+ }
+}
+
// PrebuiltSelectModuleMutator marks prebuilts that are used, either overriding source modules or
// because the source module doesn't exist. It also disables installing overridden source modules.
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
@@ -434,6 +448,8 @@
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
p := GetEmbeddedPrebuilt(prebuiltModule)
if p.usePrebuilt(ctx, s, prebuiltModule) {
+ checkInvariantsForSourceAndPrebuilt(ctx, s, prebuiltModule)
+
p.properties.UsePrebuilt = true
s.ReplacedByPrebuilt()
}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index fa40d1f..fc47cfd 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -497,6 +497,52 @@
}
}
+func testPrebuiltError(t *testing.T, expectedError, bp string) {
+ t.Helper()
+ fs := MockFS{
+ "prebuilt_file": nil,
+ }
+ GroupFixturePreparers(
+ PrepareForTestWithArchMutator,
+ PrepareForTestWithPrebuilts,
+ PrepareForTestWithOverrides,
+ fs.AddToFixture(),
+ FixtureRegisterWithContext(registerTestPrebuiltModules),
+ ).
+ ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(expectedError)).
+ RunTestWithBp(t, bp)
+}
+
+func TestPrebuiltShouldNotChangePartition(t *testing.T) {
+ testPrebuiltError(t, `partition is different`, `
+ source {
+ name: "foo",
+ vendor: true,
+ }
+ prebuilt {
+ name: "foo",
+ prefer: true,
+ srcs: ["prebuilt_file"],
+ }`)
+}
+
+func TestPrebuiltShouldNotChangePartition_WithOverride(t *testing.T) {
+ testPrebuiltError(t, `partition is different`, `
+ source {
+ name: "foo",
+ vendor: true,
+ }
+ override_source {
+ name: "bar",
+ base: "foo",
+ }
+ prebuilt {
+ name: "bar",
+ prefer: true,
+ srcs: ["prebuilt_file"],
+ }`)
+}
+
func registerTestPrebuiltBuildComponents(ctx RegistrationContext) {
registerTestPrebuiltModules(ctx)
diff --git a/android/proto.go b/android/proto.go
index 09e50c8..cebbd59 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -234,7 +234,7 @@
}
}
- tags := ApexAvailableTags(ctx.Module())
+ tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
diff --git a/android/sdk.go b/android/sdk.go
index 63e0bbe..6b598ab 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -830,6 +830,9 @@
// IsTargetBuildBeforeTiramisu return true if the target build release for which this snapshot is
// being generated is before Tiramisu, i.e. S.
IsTargetBuildBeforeTiramisu() bool
+
+ // ModuleErrorf reports an error at the line number of the module type in the module definition.
+ ModuleErrorf(fmt string, args ...interface{})
}
// ExportedComponentsInfo contains information about the components that this module exports to an
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 0ae8073..08762ef 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -100,6 +100,15 @@
return name
}
+// JavaApiLibraryNames applies JavaApiLibraryName to the list of java_library names.
+func JavaApiLibraryNames(c Config, names []string) []string {
+ apiLibs := make([]string, len(names))
+ for i, name := range names {
+ apiLibs[i] = JavaApiLibraryName(c, name)
+ }
+ return apiLibs
+}
+
func (k SdkKind) DefaultJavaLibraryName() string {
switch k {
case SdkPublic:
diff --git a/android/util.go b/android/util.go
index 38e0a4d..08a3521 100644
--- a/android/util.go
+++ b/android/util.go
@@ -26,7 +26,11 @@
// CopyOf returns a new slice that has the same contents as s.
func CopyOf(s []string) []string {
- return append([]string(nil), s...)
+ // If the input is nil, return nil and not an empty list
+ if s == nil {
+ return s
+ }
+ return append([]string{}, s...)
}
// Concat returns a new slice concatenated from the two input slices. It does not change the input
@@ -276,6 +280,8 @@
// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
// each. It modifies the slice contents in place, and returns a subslice of the original slice.
func FirstUniqueStrings(list []string) []string {
+ // Do not moodify the input in-place, operate on a copy instead.
+ list = CopyOf(list)
// 128 was chosen based on BenchmarkFirstUniqueStrings results.
if len(list) > 128 {
return firstUniqueStringsMap(list)
@@ -332,6 +338,7 @@
// SortedUniqueStrings returns what the name says
func SortedUniqueStrings(list []string) []string {
+ // FirstUniqueStrings creates a copy of `list`, so the input remains untouched.
unique := FirstUniqueStrings(list)
sort.Strings(unique)
return unique
diff --git a/android/util_test.go b/android/util_test.go
index 5584b38..a2ef589 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -381,6 +381,14 @@
}
}
+func TestCopyOfEmptyAndNil(t *testing.T) {
+ emptyList := []string{}
+ copyOfEmptyList := CopyOf(emptyList)
+ AssertBoolEquals(t, "Copy of an empty list should be an empty list and not nil", true, copyOfEmptyList != nil)
+ copyOfNilList := CopyOf(nil)
+ AssertBoolEquals(t, "Copy of a nil list should be a nil list and not an empty list", true, copyOfNilList == nil)
+}
+
func ExampleCopyOf() {
a := []string{"1", "2", "3"}
b := CopyOf(a)
diff --git a/android/variable.go b/android/variable.go
index 496f523..40eb006 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -440,6 +440,7 @@
ShippingApiLevel *string `json:",omitempty"`
+ BuildBrokenPluginValidation []string `json:",omitempty"`
BuildBrokenClangAsFlags bool `json:",omitempty"`
BuildBrokenClangCFlags bool `json:",omitempty"`
BuildBrokenClangProperty bool `json:",omitempty"`
@@ -469,6 +470,13 @@
SourceRootDirs []string `json:",omitempty"`
AfdoProfiles []string `json:",omitempty"`
+
+ ProductManufacturer string `json:",omitempty"`
+ ProductBrand string `json:",omitempty"`
+ BuildVersionTags []string `json:",omitempty"`
+
+ ReleaseVersion string `json:",omitempty"`
+ ReleaseDeviceConfigValueSets []string `json:",omitempty"`
}
func boolPtr(v bool) *bool {
@@ -537,124 +545,102 @@
Module() Module
}
-// ProductConfigProperty contains the information for a single property (may be a struct) paired
-// with the appropriate ProductConfigVariable.
+// ProductConfigOrSoongConfigProperty represents either a soong config variable + its value
+// or a product config variable. You can get both a ConfigurationAxis and a SelectKey from it
+// for use in bazel attributes. ProductVariableProperties() will return a map from properties ->
+// this interface -> property structs for use in bp2build converters
+type ProductConfigOrSoongConfigProperty interface {
+ // Name of the product variable or soong config variable
+ Name() string
+ // AlwaysEmit returns true for soong config variables but false for product variables. This
+ // is intended to indicate if we need to always emit empty lists in the select statements.
+ AlwaysEmit() bool
+ // ConfigurationAxis returns the bazel.ConfigurationAxis that represents this variable. The
+ // configuration axis will change depending on the variable and whether it's arch/os variant
+ // as well.
+ ConfigurationAxis() bazel.ConfigurationAxis
+ // SelectKey returns a string that represents the key of a select branch, however, it is not
+ // actually the real label written out to the build file.
+ // this.ConfigurationAxis().SelectKey(this.SelectKey()) will give the actual label.
+ SelectKey() string
+}
+
+// ProductConfigProperty represents a product config variable, and if it is arch-variant or not.
type ProductConfigProperty struct {
// The name of the product variable, e.g. "safestack", "malloc_not_svelte",
// "board"
- Name string
+ name string
- // Namespace of the variable, if this is a soong_config_module_type variable
- // e.g. "acme", "ANDROID", "vendor_name"
- Namespace string
-
- // Unique configuration to identify this product config property (i.e. a
- // primary key), as just using the product variable name is not sufficient.
- //
- // For product variables, this is the product variable name + optional
- // archvariant information. e.g.
- //
- // product_variables: {
- // foo: {
- // cflags: ["-Dfoo"],
- // },
- // },
- //
- // FullConfig would be "foo".
- //
- // target: {
- // android: {
- // product_variables: {
- // foo: {
- // cflags: ["-Dfoo-android"],
- // },
- // },
- // },
- // },
- //
- // FullConfig would be "foo-android".
- //
- // For soong config variables, this is the namespace + product variable name
- // + value of the variable, if applicable. The value can also be
- // conditions_default.
- //
- // e.g.
- //
- // soong_config_variables: {
- // feature1: {
- // conditions_default: {
- // cflags: ["-DDEFAULT1"],
- // },
- // cflags: ["-DFEATURE1"],
- // },
- // }
- //
- // where feature1 is created in the "acme" namespace, so FullConfig would be
- // "acme__feature1" and "acme__feature1__conditions_default".
- //
- // e.g.
- //
- // soong_config_variables: {
- // board: {
- // soc_a: {
- // cflags: ["-DSOC_A"],
- // },
- // soc_b: {
- // cflags: ["-DSOC_B"],
- // },
- // soc_c: {},
- // conditions_default: {
- // cflags: ["-DSOC_DEFAULT"]
- // },
- // },
- // }
- //
- // where board is created in the "acme" namespace, so FullConfig would be
- // "acme__board__soc_a", "acme__board__soc_b", and
- // "acme__board__conditions_default"
- FullConfig string
-
- // keeps track of whether this product variable is nested under an arch variant
- OuterAxis bazel.ConfigurationAxis
+ arch string
}
-func (p *ProductConfigProperty) AlwaysEmit() bool {
- return p.Namespace != ""
+func (p ProductConfigProperty) Name() string {
+ return p.name
}
-func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
- if p.Namespace == "" {
- return bazel.ProductVariableConfigurationAxis(p.FullConfig, p.OuterAxis)
+func (p ProductConfigProperty) AlwaysEmit() bool {
+ return false
+}
+
+func (p ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
+ return bazel.ProductVariableConfigurationAxis(p.arch != "", p.name+"__"+p.arch)
+}
+
+func (p ProductConfigProperty) SelectKey() string {
+ if p.arch == "" {
+ return strings.ToLower(p.name)
} else {
- // Soong config variables can be uniquely identified by the namespace
- // (e.g. acme, android) and the product variable name (e.g. board, size)
- return bazel.ProductVariableConfigurationAxis(p.Namespace+"__"+p.Name, bazel.NoConfigAxis)
+ return strings.ToLower(p.name + "-" + p.arch)
}
}
+// SoongConfigProperty represents a soong config variable, its value if it's a string variable,
+// and if it's dependent on the OS or not
+type SoongConfigProperty struct {
+ name string
+ namespace string
+ // Can be an empty string for bool/value soong config variables
+ value string
+ // If there is a target: field inside a soong config property struct, the os that it selects
+ // on will be represented here.
+ os string
+}
+
+func (p SoongConfigProperty) Name() string {
+ return p.name
+}
+
+func (p SoongConfigProperty) AlwaysEmit() bool {
+ return true
+}
+
+func (p SoongConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
+ return bazel.ProductVariableConfigurationAxis(false, p.namespace+"__"+p.name+"__"+p.os)
+}
+
// SelectKey returns the literal string that represents this variable in a BUILD
// select statement.
-func (p *ProductConfigProperty) SelectKey() string {
- if p.Namespace == "" {
- return strings.ToLower(p.FullConfig)
- }
-
- if p.FullConfig == bazel.ConditionsDefaultConfigKey {
+func (p SoongConfigProperty) SelectKey() string {
+ // p.value being conditions_default can happen with or without a desired os. When not using
+ // an os, we want to emit literally just //conditions:default in the select statement, but
+ // when using an os, we want to emit namespace__name__conditions_default__os, so that
+ // the branch is only taken if the variable is not set, and we're on the desired os.
+ // ConfigurationAxis#SelectKey will map the conditions_default result of this function to
+ // //conditions:default.
+ if p.value == bazel.ConditionsDefaultConfigKey && p.os == "" {
return bazel.ConditionsDefaultConfigKey
}
- value := p.FullConfig
- if value == p.Name {
- value = ""
+ parts := []string{p.namespace, p.name}
+ if p.value != "" && p.value != bazel.ConditionsDefaultSelectKey {
+ parts = append(parts, p.value)
+ }
+ if p.os != "" {
+ parts = append(parts, p.os)
}
- // e.g. acme__feature1, android__board__soc_a
- selectKey := strings.ToLower(strings.Join([]string{p.Namespace, p.Name}, "__"))
- if value != "" {
- selectKey = strings.ToLower(strings.Join([]string{selectKey, value}, "__"))
- }
-
- return selectKey
+ // e.g. acme__feature1, android__board__soc_a, my_namespace__my_variables__my_value__my_os
+ return strings.ToLower(strings.Join(parts, "__"))
}
// ProductConfigProperties is a map of maps to group property values according
@@ -670,7 +656,7 @@
//
// The value of the map is the interface{} representing the value of the
// property, like ["-DDEFINES"] for cflags.
-type ProductConfigProperties map[string]map[ProductConfigProperty]interface{}
+type ProductConfigProperties map[string]map[ProductConfigOrSoongConfigProperty]interface{}
// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
// have been set for the given module.
@@ -681,26 +667,10 @@
if moduleBase.variableProperties != nil {
productVariablesProperty := proptools.FieldNameForProperty("product_variables")
- productVariableValues(
- productVariablesProperty,
- moduleBase.variableProperties,
- "",
- "",
- &productConfigProperties,
- bazel.ConfigurationAxis{},
- )
-
- for axis, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
+ for /* axis */ _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
for config, props := range configToProps {
- // GetArchVariantProperties is creating an instance of the requested type
- // and productVariablesValues expects an interface, so no need to cast
- productVariableValues(
- productVariablesProperty,
- props,
- "",
- config,
- &productConfigProperties,
- axis)
+ variableValues := reflect.ValueOf(props).Elem().FieldByName(productVariablesProperty)
+ productConfigProperties.AddProductConfigProperties(variableValues, config)
}
}
}
@@ -708,13 +678,8 @@
if m, ok := module.(Bazelable); ok && m.namespacedVariableProps() != nil {
for namespace, namespacedVariableProps := range m.namespacedVariableProps() {
for _, namespacedVariableProp := range namespacedVariableProps {
- productVariableValues(
- soongconfig.SoongConfigProperty,
- namespacedVariableProp,
- namespace,
- "",
- &productConfigProperties,
- bazel.NoConfigAxis)
+ variableValues := reflect.ValueOf(namespacedVariableProp).Elem().FieldByName(soongconfig.SoongConfigProperty)
+ productConfigProperties.AddSoongConfigProperties(namespace, variableValues)
}
}
}
@@ -723,30 +688,49 @@
}
func (p *ProductConfigProperties) AddProductConfigProperty(
- propertyName, namespace, productVariableName, config string, property interface{}, outerAxis bazel.ConfigurationAxis) {
- if (*p)[propertyName] == nil {
- (*p)[propertyName] = make(map[ProductConfigProperty]interface{})
- }
+ propertyName, productVariableName, arch string, propertyValue interface{}) {
productConfigProp := ProductConfigProperty{
- Namespace: namespace, // e.g. acme, android
- Name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
- FullConfig: config, // e.g. size, feature1-x86, size__conditions_default
- OuterAxis: outerAxis,
+ name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
+ arch: arch, // e.g. "", x86, arm64
}
- if existing, ok := (*p)[propertyName][productConfigProp]; ok && namespace != "" {
+ p.AddEitherProperty(propertyName, productConfigProp, propertyValue)
+}
+
+func (p *ProductConfigProperties) AddSoongConfigProperty(
+ propertyName, namespace, variableName, value, os string, propertyValue interface{}) {
+
+ soongConfigProp := SoongConfigProperty{
+ namespace: namespace,
+ name: variableName, // e.g. size, feature1, feature2, FEATURE3, board
+ value: value,
+ os: os, // e.g. android, linux_x86
+ }
+
+ p.AddEitherProperty(propertyName, soongConfigProp, propertyValue)
+}
+
+func (p *ProductConfigProperties) AddEitherProperty(
+ propertyName string, key ProductConfigOrSoongConfigProperty, propertyValue interface{}) {
+ if (*p)[propertyName] == nil {
+ (*p)[propertyName] = make(map[ProductConfigOrSoongConfigProperty]interface{})
+ }
+
+ if existing, ok := (*p)[propertyName][key]; ok {
switch dst := existing.(type) {
case []string:
- if src, ok := property.([]string); ok {
- dst = append(dst, src...)
- (*p)[propertyName][productConfigProp] = dst
+ src, ok := propertyValue.([]string)
+ if !ok {
+ panic("Conflicting types")
}
+ dst = append(dst, src...)
+ (*p)[propertyName][key] = dst
default:
- panic(fmt.Errorf("TODO: handle merging value %s", existing))
+ panic(fmt.Errorf("TODO: handle merging value %#v", existing))
}
} else {
- (*p)[propertyName][productConfigProp] = property
+ (*p)[propertyName][key] = propertyValue
}
}
@@ -783,10 +767,7 @@
return v, true
}
-func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(namespace, suffix string, variableValues reflect.Value, outerAxis bazel.ConfigurationAxis) {
- // variableValues can either be a product_variables or
- // soong_config_variables struct.
- //
+func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(variableValues reflect.Value, arch string) {
// Example of product_variables:
//
// product_variables: {
@@ -799,35 +780,7 @@
// ],
// },
// },
- //
- // Example of soong_config_variables:
- //
- // soong_config_variables: {
- // feature1: {
- // conditions_default: {
- // ...
- // },
- // cflags: ...
- // },
- // feature2: {
- // cflags: ...
- // conditions_default: {
- // ...
- // },
- // },
- // board: {
- // soc_a: {
- // ...
- // },
- // soc_a: {
- // ...
- // },
- // soc_c: {},
- // conditions_default: {
- // ...
- // },
- // },
- // }
+
for i := 0; i < variableValues.NumField(); i++ {
// e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
productVariableName := variableValues.Type().Field(i).Name
@@ -839,25 +792,78 @@
continue
}
- // Unlike product variables, config variables require a few more
- // indirections to extract the struct from the reflect.Value.
- if v, ok := maybeExtractConfigVarProp(variableValue); ok {
- variableValue = v
- }
-
for j := 0; j < variableValue.NumField(); j++ {
property := variableValue.Field(j)
// e.g. Asflags, Cflags, Enabled, etc.
propertyName := variableValue.Type().Field(j).Name
- // config can also be "conditions_default".
- config := proptools.PropertyNameForField(propertyName)
+ if property.Kind() != reflect.Interface {
+ productConfigProperties.AddProductConfigProperty(propertyName, productVariableName, arch, property.Interface())
+ }
+ }
+ }
+
+}
+
+func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties(namespace string, soongConfigVariablesStruct reflect.Value) {
+ //
+ // Example of soong_config_variables:
+ //
+ // soong_config_variables: {
+ // feature1: {
+ // conditions_default: {
+ // ...
+ // },
+ // cflags: ...
+ // },
+ // feature2: {
+ // cflags: ...
+ // conditions_default: {
+ // ...
+ // },
+ // },
+ // board: {
+ // soc_a: {
+ // ...
+ // },
+ // soc_b: {
+ // ...
+ // },
+ // soc_c: {},
+ // conditions_default: {
+ // ...
+ // },
+ // },
+ // }
+ for i := 0; i < soongConfigVariablesStruct.NumField(); i++ {
+ // e.g. feature1, feature2, board
+ variableName := soongConfigVariablesStruct.Type().Field(i).Name
+ variableStruct := soongConfigVariablesStruct.Field(i)
+ // Check if any properties were set for the module
+ if variableStruct.IsZero() {
+ // e.g. feature1: {}
+ continue
+ }
+
+ // Unlike product variables, config variables require a few more
+ // indirections to extract the struct from the reflect.Value.
+ if v, ok := maybeExtractConfigVarProp(variableStruct); ok {
+ variableStruct = v
+ }
+
+ for j := 0; j < variableStruct.NumField(); j++ {
+ propertyOrStruct := variableStruct.Field(j)
+ // propertyOrValueName can either be:
+ // - A property, like: Asflags, Cflags, Enabled, etc.
+ // - A soong config string variable's value, like soc_a, soc_b, soc_c in the example above
+ // - "conditions_default"
+ propertyOrValueName := variableStruct.Type().Field(j).Name
// If the property wasn't set, no need to pass it along
- if property.IsZero() {
+ if propertyOrStruct.IsZero() {
continue
}
- if v, ok := maybeExtractConfigVarProp(property); ok {
+ if v, ok := maybeExtractConfigVarProp(propertyOrStruct); ok {
// The field is a struct, which is used by:
// 1) soong_config_string_variables
//
@@ -875,6 +881,9 @@
// cflags: ...,
// static_libs: ...
// }
+ //
+ // This means that propertyOrValueName is either conditions_default, or a soong
+ // config string variable's value.
field := v
// Iterate over fields of this struct prop.
for k := 0; k < field.NumField(); k++ {
@@ -884,47 +893,59 @@
if field.Field(k).IsZero() && namespace == "" {
continue
}
- actualPropertyName := field.Type().Field(k).Name
- productConfigProperties.AddProductConfigProperty(
- actualPropertyName, // e.g. cflags, static_libs
- namespace, // e.g. acme, android
- productVariableName, // e.g. size, feature1, FEATURE2, board
- config,
- field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"],
- outerAxis,
- )
+ propertyName := field.Type().Field(k).Name
+ if propertyName == "Target" {
+ productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), field.Field(k))
+ } else if propertyName == "Arch" || propertyName == "Multilib" {
+ panic("Arch/Multilib are not currently supported in soong config variable structs")
+ } else {
+ productConfigProperties.AddSoongConfigProperty(propertyName, namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), "", field.Field(k).Interface())
+ }
}
- } else if property.Kind() != reflect.Interface {
+ } else if propertyOrStruct.Kind() != reflect.Interface {
// If not an interface, then this is not a conditions_default or
- // a struct prop. That is, this is a regular product variable,
- // or a bool/value config variable.
- config := productVariableName + suffix
- productConfigProperties.AddProductConfigProperty(
- propertyName,
- namespace,
- productVariableName,
- config,
- property.Interface(),
- outerAxis,
- )
+ // a struct prop. That is, this is a bool/value config variable.
+ if propertyOrValueName == "Target" {
+ productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, "", propertyOrStruct)
+ } else if propertyOrValueName == "Arch" || propertyOrValueName == "Multilib" {
+ panic("Arch/Multilib are not currently supported in soong config variable structs")
+ } else {
+ productConfigProperties.AddSoongConfigProperty(propertyOrValueName, namespace, variableName, "", "", propertyOrStruct.Interface())
+ }
}
}
}
}
-// productVariableValues uses reflection to convert a property struct for
-// product_variables and soong_config_variables to structs that can be generated
-// as select statements.
-func productVariableValues(
- fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties, outerAxis bazel.ConfigurationAxis) {
- if suffix != "" {
- suffix = "-" + suffix
- }
+func (productConfigProperties *ProductConfigProperties) AddSoongConfigPropertiesFromTargetStruct(namespace, soongConfigVariableName string, soongConfigVariableValue string, targetStruct reflect.Value) {
+ // targetStruct will be a struct with fields like "android", "host", "arm", "x86",
+ // "android_arm", etc. The values of each of those fields will be a regular property struct.
+ for i := 0; i < targetStruct.NumField(); i++ {
+ targetFieldName := targetStruct.Type().Field(i).Name
+ archOrOsSpecificStruct := targetStruct.Field(i)
+ for j := 0; j < archOrOsSpecificStruct.NumField(); j++ {
+ property := archOrOsSpecificStruct.Field(j)
+ // e.g. Asflags, Cflags, Enabled, etc.
+ propertyName := archOrOsSpecificStruct.Type().Field(j).Name
- // variableValues represent the product_variables or soong_config_variables struct.
- variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
- productConfigProperties.AddProductConfigProperties(namespace, suffix, variableValues, outerAxis)
+ if targetFieldName == "Android" {
+ productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, "android", property.Interface())
+ } else if targetFieldName == "Host" {
+ for _, os := range osTypeList {
+ if os.Class == Host {
+ productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, os.Name, property.Interface())
+ }
+ }
+ } else {
+ // One problem with supporting additional fields is that if multiple branches of
+ // "target" overlap, we don't want them to be in the same select statement (aka
+ // configuration axis). "android" and "host" are disjoint, so it's ok that we only
+ // have 2 axes right now. (soongConfigVariables and soongConfigVariablesPlusOs)
+ panic("TODO: support other target types in soong config variable structs: " + targetFieldName)
+ }
+ }
+ }
}
func VariableMutator(mctx BottomUpMutatorContext) {
diff --git a/apex/Android.bp b/apex/Android.bp
index 61d7fb2..0791497 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -29,7 +29,6 @@
"bp2build.go",
"deapexer.go",
"key.go",
- "metadata.go",
"prebuilt.go",
"testing.go",
"vndk.go",
@@ -39,7 +38,6 @@
"bootclasspath_fragment_test.go",
"classpath_element_test.go",
"dexpreopt_bootjars_test.go",
- "metadata_test.go",
"platform_bootclasspath_test.go",
"systemserver_classpath_fragment_test.go",
"vndk_test.go",
diff --git a/apex/apex.go b/apex/apex.go
index 7fb6f50..1c79463 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -137,6 +137,10 @@
// List of filesystem images that are embedded inside this APEX bundle.
Filesystems []string
+ // The minimum SDK version that this APEX must support at minimum. This is usually set to
+ // the SDK version that the APEX was first introduced.
+ Min_sdk_version *string
+
// Whether this APEX is considered updatable or not. When set to true, this will enforce
// additional rules for making sure that the APEX is truly updatable. To be updatable,
// min_sdk_version should be set as well. This will also disable the size optimizations like
@@ -380,10 +384,6 @@
// Trim against a specific Dynamic Common Lib APEX
Trim_against *string
-
- // The minimum SDK version that this APEX must support at minimum. This is usually set to
- // the SDK version that the APEX was first introduced.
- Min_sdk_version *string
}
type apexBundle struct {
@@ -404,7 +404,7 @@
///////////////////////////////////////////////////////////////////////////////////////////
// Inputs
- // Keys for apex_paylaod.img
+ // Keys for apex_payload.img
publicKeyFile android.Path
privateKeyFile android.Path
@@ -1064,6 +1064,10 @@
apexVariationName := mctx.ModuleName() // could be com.android.foo
a.properties.ApexVariationName = apexVariationName
+ testApexes := []string{}
+ if a.testApex {
+ testApexes = []string{apexVariationName}
+ }
apexInfo := android.ApexInfo{
ApexVariationName: apexVariationName,
MinSdkVersion: minSdkVersion,
@@ -1072,6 +1076,7 @@
InApexVariants: []string{apexVariationName},
InApexModules: []string{a.Name()}, // could be com.mycompany.android.foo
ApexContents: []*android.ApexContents{apexContents},
+ TestApexes: testApexes,
}
mctx.WalkDeps(func(child, parent android.Module) bool {
if !continueApexDepsWalk(child, parent) {
@@ -1823,6 +1828,7 @@
Certificate() java.Certificate
BaseModuleName() string
LintDepSets() java.LintDepSets
+ PrivAppAllowlist() android.OptionalPath
}
var _ androidApp = (*java.AndroidApp)(nil)
@@ -1843,7 +1849,7 @@
return buildId
}
-func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp androidApp) apexFile {
+func apexFilesForAndroidApp(ctx android.BaseModuleContext, aapp androidApp) []apexFile {
appDir := "app"
if aapp.Privileged() {
appDir = "priv-app"
@@ -1865,7 +1871,15 @@
}); ok {
af.overriddenPackageName = app.OverriddenManifestPackageName()
}
- return af
+ apexFiles := []apexFile{af}
+
+ if allowlist := aapp.PrivAppAllowlist(); allowlist.Valid() {
+ dirInApex := filepath.Join("etc", "permissions")
+ privAppAllowlist := newApexFile(ctx, allowlist.Path(), aapp.BaseModuleName()+"privapp", dirInApex, etc, aapp)
+ apexFiles = append(apexFiles, privAppAllowlist)
+ }
+
+ return apexFiles
}
func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, rro java.RuntimeResourceOverlayModule) apexFile {
@@ -1959,9 +1973,6 @@
// overridden by different override_apex modules (e.g. Google or Go variants),
// which is handled by the overrides mutators.
func (a *apexBundle) GetBazelLabel(ctx android.BazelConversionPathContext, module blueprint.Module) string {
- if _, ok := ctx.Module().(android.OverridableModule); ok {
- return android.MaybeBp2buildLabelOfOverridingModule(ctx)
- }
return a.BazelModuleBase.GetBazelLabel(ctx, a)
}
@@ -2310,12 +2321,12 @@
case androidAppTag:
switch ap := child.(type) {
case *java.AndroidApp:
- vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
return true // track transitive dependencies
case *java.AndroidAppImport:
- vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
case *java.AndroidTestHelperApp:
- vctx.filesInfo = append(vctx.filesInfo, apexFileForAndroidApp(ctx, ap))
+ vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
case *java.AndroidAppSet:
appDir := "app"
if ap.Privileged() {
@@ -2595,8 +2606,45 @@
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
vctx.normalizeFileInfo(ctx)
if a.privateKeyFile == nil {
- ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.overridableProperties.Key))
- return
+ if ctx.Config().AllowMissingDependencies() {
+ // TODO(b/266099037): a better approach for slim manifests.
+ ctx.AddMissingDependencies([]string{String(a.overridableProperties.Key)})
+ // Create placeholder paths for later stages that expect to see those paths,
+ // though they won't be used.
+ var unusedPath = android.PathForModuleOut(ctx, "nonexistentprivatekey")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.ErrorRule,
+ Output: unusedPath,
+ Args: map[string]string{
+ "error": "Private key not available",
+ },
+ })
+ a.privateKeyFile = unusedPath
+ } else {
+ ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.overridableProperties.Key))
+ return
+ }
+ }
+
+ if a.publicKeyFile == nil {
+ if ctx.Config().AllowMissingDependencies() {
+ // TODO(b/266099037): a better approach for slim manifests.
+ ctx.AddMissingDependencies([]string{String(a.overridableProperties.Key)})
+ // Create placeholder paths for later stages that expect to see those paths,
+ // though they won't be used.
+ var unusedPath = android.PathForModuleOut(ctx, "nonexistentpublickey")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.ErrorRule,
+ Output: unusedPath,
+ Args: map[string]string{
+ "error": "Public key not available",
+ },
+ })
+ a.publicKeyFile = unusedPath
+ } else {
+ ctx.PropertyErrorf("key", "public_key for %q could not be found", String(a.overridableProperties.Key))
+ return
+ }
}
////////////////////////////////////////////////////////////////////////////////////////////
@@ -2924,7 +2972,7 @@
// Only override the minSdkVersion value on Apexes which already specify
// a min_sdk_version (it's optional for non-updatable apexes), and that its
// min_sdk_version value is lower than the one to override with.
- minApiLevel := minSdkVersionFromValue(ctx, proptools.String(a.overridableProperties.Min_sdk_version))
+ minApiLevel := minSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version))
if minApiLevel.IsNone() {
return ""
}
@@ -3215,7 +3263,6 @@
//
m["com.android.appsearch"] = []string{
"icing-java-proto-lite",
- "libprotobuf-java-lite",
}
//
// Module separator
@@ -3226,16 +3273,13 @@
//
// Module separator
//
- m["com.android.cellbroadcast"] = []string{"CellBroadcastApp", "CellBroadcastServiceModule"}
+ m["com.android.cellbroadcast"] = []string{}
//
// Module separator
//
m["com.android.extservices"] = []string{
- "error_prone_annotations",
"ExtServices-core",
- "ExtServices",
"libtextclassifier-java",
- "libz_current",
"textclassifier-statsd",
"TextClassifierNotificationLibNoManifest",
"TextClassifierServiceLibNoManifest",
@@ -3253,8 +3297,6 @@
"android.hidl.memory@1.0",
"android.hidl.safe_union@1.0",
"libarect",
- "libbuildversion",
- "libmath",
"libprocpartition",
}
//
@@ -3284,15 +3326,12 @@
// Module separator
//
m["com.android.runtime"] = []string{
- "bionic_libc_platform_headers",
- "libarm-optimized-routines-math",
"libc_aeabi",
"libc_bionic",
"libc_bionic_ndk",
"libc_bootstrap",
"libc_common",
"libc_common_shared",
- "libc_common_static",
"libc_dns",
"libc_dynamic_dispatch",
"libc_fortify",
@@ -3309,19 +3348,16 @@
"libc_openbsd_large_stack",
"libc_openbsd_ndk",
"libc_pthread",
- "libc_static_dispatch",
"libc_syscalls",
"libc_tzcode",
"libc_unwind_static",
"libdebuggerd",
"libdebuggerd_common_headers",
"libdebuggerd_handler_core",
- "libdebuggerd_handler_fallback",
"libdl_static",
"libjemalloc5",
"liblinker_main",
"liblinker_malloc",
- "liblz4",
"liblzma",
"libprocinfo",
"libpropertyinfoparser",
@@ -3339,17 +3375,7 @@
m["com.android.tethering"] = []string{
"android.hardware.tetheroffload.config-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
- "android.hidl.base-V1.0-java",
- "libcgrouprc",
- "libcgrouprc_format",
- "libtetherutilsjni",
- "libvndksupport",
"net-utils-framework-common",
- "netd_aidl_interface-V3-java",
- "netlink-client",
- "networkstack-aidl-interfaces-java",
- "tethering-aidl-interfaces-java",
- "TetheringApiCurrentLib",
}
//
// Module separator
@@ -3369,57 +3395,22 @@
"android.hardware.wifi.supplicant-V1.1-java",
"android.hardware.wifi.supplicant-V1.2-java",
"android.hardware.wifi.supplicant-V1.3-java",
- "android.hidl.base-V1.0-java",
- "android.hidl.manager-V1.0-java",
- "android.hidl.manager-V1.1-java",
- "android.hidl.manager-V1.2-java",
"bouncycastle-unbundled",
- "dnsresolver_aidl_interface-V2-java",
- "error_prone_annotations",
- "framework-wifi-pre-jarjar",
"framework-wifi-util-lib",
- "ipmemorystore-aidl-interfaces-V3-java",
- "ipmemorystore-aidl-interfaces-java",
"ksoap2",
"libnanohttpd",
- "libwifi-jni",
- "net-utils-services-common",
- "netd_aidl_interface-V2-java",
- "netd_aidl_interface-unstable-java",
- "netd_event_listener_interface-java",
- "netlink-client",
- "networkstack-client",
- "services.net",
"wifi-lite-protos",
"wifi-nano-protos",
"wifi-service-pre-jarjar",
- "wifi-service-resources",
- }
- //
- // Module separator
- //
- m["com.android.os.statsd"] = []string{
- "libstatssocket",
}
//
// Module separator
//
m[android.AvailableToAnyApex] = []string{
- // TODO(b/156996905) Set apex_available/min_sdk_version for androidx/extras support libraries
- "androidx",
- "androidx-constraintlayout_constraintlayout",
- "androidx-constraintlayout_constraintlayout-nodeps",
- "androidx-constraintlayout_constraintlayout-solver",
- "androidx-constraintlayout_constraintlayout-solver-nodeps",
- "com.google.android.material_material",
- "com.google.android.material_material-nodeps",
-
- "libclang_rt",
"libprofile-clang-extras",
"libprofile-clang-extras_ndk",
"libprofile-extras",
"libprofile-extras_ndk",
- "libunwind",
}
return m
}
@@ -3575,8 +3566,8 @@
// TODO(b/219503907) this would need to be set to a.MinSdkVersionValue(ctx) but
// given it's coming via config, we probably don't want to put it in here.
var minSdkVersion bazel.StringAttribute
- if a.overridableProperties.Min_sdk_version != nil {
- minSdkVersion.SetValue(*a.overridableProperties.Min_sdk_version)
+ if a.properties.Min_sdk_version != nil {
+ minSdkVersion.SetValue(*a.properties.Min_sdk_version)
}
if props, ok := productVariableProps[minSdkVersionPropName]; ok {
for c, p := range props {
@@ -3682,6 +3673,8 @@
commonAttrs := android.CommonAttributes{}
if a.testApex {
commonAttrs.Testonly = proptools.BoolPtr(true)
+ // Set the api_domain of the test apex
+ attrs.Base_apex_name = proptools.StringPtr(cc.GetApiDomain(a.Name()))
}
return attrs, props, commonAttrs
@@ -3790,3 +3783,7 @@
func invalidCompileMultilib(ctx android.TopDownMutatorContext, value string) {
ctx.PropertyErrorf("compile_multilib", "Invalid value: %s", value)
}
+
+func (a *apexBundle) IsTestApex() bool {
+ return a.testApex
+}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 1581949..ebc35cf 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -23,7 +23,11 @@
)
func init() {
- android.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
+ registerApexDepsInfoComponents(android.InitRegistrationContext)
+}
+
+func registerApexDepsInfoComponents(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
}
type apexDepsInfoSingleton struct {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 139b77e..c1d80a3 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -33,6 +33,7 @@
"android/soong/cc"
"android/soong/dexpreopt"
prebuilt_etc "android/soong/etc"
+ "android/soong/filesystem"
"android/soong/java"
"android/soong/rust"
"android/soong/sh"
@@ -1367,6 +1368,8 @@
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
+ static_libs: ["libstatic"],
+ shared_libs: ["libshared"],
runtime_libs: ["libfoo", "libbar"],
system_shared_libs: [],
stl: "none",
@@ -1391,6 +1394,39 @@
apex_available: [ "myapex" ],
}
+ cc_library {
+ name: "libstatic",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ runtime_libs: ["libstatic_to_runtime"],
+ }
+
+ cc_library {
+ name: "libshared",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ runtime_libs: ["libshared_to_runtime"],
+ }
+
+ cc_library {
+ name: "libstatic_to_runtime",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "libshared_to_runtime",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
@@ -1404,11 +1440,14 @@
// Ensure that runtime_libs dep in included
ensureContains(t, copyCmds, "image.apex/lib64/libbar.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libshared.so")
+ ensureContains(t, copyCmds, "image.apex/lib64/libshared_to_runtime.so")
+
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libstatic_to_runtime.so")
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
-
}
var prepareForTestOfRuntimeApexWithHwasan = android.GroupFixturePreparers(
@@ -1460,6 +1499,10 @@
sanitize: {
never: true,
},
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
} `)
ctx := result.TestContext
@@ -1508,6 +1551,10 @@
sanitize: {
never: true,
},
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
}
`)
ctx := result.TestContext
@@ -1980,6 +2027,93 @@
android.AssertStringDoesContain(t, "cflags", cflags, "-target aarch64-linux-android29")
}
+func TestTrackAllowedDeps(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: true,
+ native_shared_libs: [
+ "mylib",
+ "yourlib",
+ ],
+ min_sdk_version: "29",
+ }
+
+ apex {
+ name: "myapex2",
+ key: "myapex.key",
+ updatable: false,
+ native_shared_libs: ["yourlib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libbar"],
+ min_sdk_version: "29",
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stubs: { versions: ["29", "30"] },
+ }
+
+ cc_library {
+ name: "yourlib",
+ srcs: ["mylib.cpp"],
+ min_sdk_version: "29",
+ apex_available: ["myapex", "myapex2", "//apex_available:platform"],
+ }
+ `, withFiles(android.MockFS{
+ "packages/modules/common/build/allowed_deps.txt": nil,
+ }))
+
+ depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+ inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
+ android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs,
+ "out/soong/.intermediates/myapex/android_common_myapex_image/depsinfo/flatlist.txt")
+ android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
+ "out/soong/.intermediates/myapex2/android_common_myapex2_image/depsinfo/flatlist.txt")
+
+ myapex := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+ flatlist := strings.Split(myapex.Output("depsinfo/flatlist.txt").BuildParams.Args["content"], "\\n")
+ android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
+ flatlist, "libbar(minSdkVersion:(no version)) (external)")
+ android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
+ flatlist, "mylib:(minSdkVersion:29)")
+ android.AssertStringListContains(t, "track platform-available lib",
+ flatlist, "yourlib(minSdkVersion:29)")
+}
+
+func TestTrackAllowedDeps_SkipWithoutAllowedDepsTxt(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: true,
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+ depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+ if nil != depsinfo.MaybeRule("generateApexDepsInfoFilesRule").Output {
+ t.Error("apex_depsinfo_singleton shouldn't run when allowed_deps.txt doesn't exist")
+ }
+}
+
func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
ctx := testApex(t, `
apex {
@@ -3131,10 +3265,7 @@
stubs: {
versions: ["1", "2", "3"],
},
- apex_available: [
- "//apex_available:platform",
- "myapex",
- ],
+ apex_available: ["myapex"],
}
cc_binary {
@@ -4302,7 +4433,7 @@
apex {
name: "myapex_selfcontained",
key: "myapex.key",
- native_shared_libs: ["lib_dep", "libfoo"],
+ native_shared_libs: ["lib_dep_on_bar", "libbar"],
compile_multilib: "both",
file_contexts: ":myapex-file_contexts",
updatable: false,
@@ -4336,6 +4467,18 @@
}
cc_library {
+ name: "lib_dep_on_bar",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libbar"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex_selfcontained",
+ ],
+ }
+
+
+ cc_library {
name: "libfoo",
srcs: ["mytest.cpp"],
stubs: {
@@ -4345,9 +4488,22 @@
stl: "none",
apex_available: [
"myapex_provider",
+ ],
+ }
+
+ cc_library {
+ name: "libbar",
+ srcs: ["mytest.cpp"],
+ stubs: {
+ versions: ["1"],
+ },
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
"myapex_selfcontained",
],
}
+
`)
var apexManifestRule android.TestingBuildParams
@@ -4374,7 +4530,7 @@
apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule")
provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
- ensureListContains(t, provideNativeLibs, "libfoo.so")
+ ensureListContains(t, provideNativeLibs, "libbar.so")
ensureListEmpty(t, requireNativeLibs)
}
@@ -5857,67 +6013,6 @@
})
}
-func TestPrebuiltSkipsSymbols(t *testing.T) {
- testCases := []struct {
- name string
- usePrebuilt bool
- installSymbolFiles bool
- }{
- {
- name: "Source module build rule doesn't install symbol files",
- usePrebuilt: true,
- installSymbolFiles: false,
- },
- {
- name: "Source module is installed with symbols",
- usePrebuilt: false,
- installSymbolFiles: true,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- preferProperty := "prefer: false"
- if tc.usePrebuilt {
- preferProperty = "prefer: true"
- }
- ctx := testApex(t, `
- // Source module
- apex {
- name: "myapex",
- binaries: ["foo"],
- key: "myapex.key",
- updatable: false,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- apex_set {
- name: "myapex",
- set: "myapex.apks",
- `+preferProperty+`
- }
-
- cc_binary {
- name: "foo",
- srcs: ["mylib.cpp"],
- system_shared_libs: [],
- stl: "none",
- apex_available: [ "myapex" ],
- }
- `)
- // Symbol files are installed by installing entries under ${OUT}/apex/{apex name}
- android.AssertStringListContainsEquals(t, "Installs",
- ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().FilesToInstall().Strings(),
- filepath.Join(ctx.Config().SoongOutDir(), "target/product/test_device/apex/myapex/bin/foo"),
- tc.installSymbolFiles)
- })
- }
-}
-
func TestApexWithTests(t *testing.T) {
ctx := testApex(t, `
apex_test {
@@ -6165,6 +6260,8 @@
sdk_version: "current",
system_modules: "none",
privileged: true,
+ privapp_allowlist: "perms.xml",
+ package_name: "com.android.AppFooPriv",
stl: "none",
apex_available: [ "myapex" ],
}
@@ -6194,6 +6291,7 @@
ensureContains(t, copyCmds, "image.apex/app/AppFoo@TEST.BUILD_ID/AppFoo.apk")
ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv@TEST.BUILD_ID/AppFooPriv.apk")
+ ensureContains(t, copyCmds, "image.apex/etc/permissions/privapp_allowlist_com.android.AppFooPriv.xml")
appZipRule := ctx.ModuleForTests("AppFoo", "android_common_apex10000").Description("zip jni libs")
// JNI libraries are uncompressed
@@ -6481,6 +6579,72 @@
}`)
}
+func TestApexAvailable_IndirectStaticDep(t *testing.T) {
+ testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ static_libs: ["libbar"],
+ system_shared_libs: [],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ shared_libs: ["libbaz"],
+ system_shared_libs: [],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbaz",
+ stl: "none",
+ system_shared_libs: [],
+ }`)
+
+ testApexError(t, `requires "libbar" that doesn't list the APEX under 'apex_available'.`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ stl: "none",
+ static_libs: ["libbar"],
+ system_shared_libs: [],
+ apex_available: ["myapex"],
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ system_shared_libs: [],
+ }`)
+}
+
func TestApexAvailable_InvalidApexName(t *testing.T) {
testApexError(t, "\"otherapex\" is not a valid module name", `
apex {
@@ -8717,14 +8881,14 @@
apex {
name: "com.android.art",
key: "myapex.key",
- native_shared_libs: ["mylib"],
+ native_shared_libs: ["libnativebridge"],
updatable: false,
}
apex {
name: "com.android.art.debug",
key: "myapex.key",
- native_shared_libs: ["mylib", "mytestlib"],
+ native_shared_libs: ["libnativebridge", "libnativebrdige_test"],
updatable: false,
}
@@ -8735,8 +8899,8 @@
}
cc_library {
- name: "mylib",
- srcs: ["mylib.cpp"],
+ name: "libnativebridge",
+ srcs: ["libnativebridge.cpp"],
system_shared_libs: [],
stl: "none",
stubs: {
@@ -8746,10 +8910,10 @@
}
cc_library {
- name: "mytestlib",
+ name: "libnativebrdige_test",
srcs: ["mylib.cpp"],
system_shared_libs: [],
- shared_libs: ["mylib"],
+ shared_libs: ["libnativebridge"],
stl: "none",
apex_available: ["com.android.art.debug"],
test_for: ["com.android.art"],
@@ -10421,3 +10585,128 @@
// Ensure that canned_fs_config has "cat my_config" at the end
ensureContains(t, cmd, `( echo '/ 1000 1000 0755'; echo '/apex_manifest.json 1000 1000 0644'; echo '/apex_manifest.pb 1000 1000 0644'; cat my_config ) >`)
}
+
+func TestStubLibrariesMultipleApexViolation(t *testing.T) {
+ testCases := []struct {
+ desc string
+ hasStubs bool
+ apexAvailable string
+ expectedError string
+ }{
+ {
+ desc: "non-stub library can have multiple apex_available",
+ hasStubs: false,
+ apexAvailable: `["myapex", "otherapex"]`,
+ },
+ {
+ desc: "stub library should not be available to anyapex",
+ hasStubs: true,
+ apexAvailable: `["//apex_available:anyapex"]`,
+ expectedError: "Stub libraries should have a single apex_available.*anyapex",
+ },
+ {
+ desc: "stub library should not be available to multiple apexes",
+ hasStubs: true,
+ apexAvailable: `["myapex", "otherapex"]`,
+ expectedError: "Stub libraries should have a single apex_available.*myapex.*otherapex",
+ },
+ {
+ desc: "stub library can be available to a core apex and a test apex",
+ hasStubs: true,
+ apexAvailable: `["myapex", "test_myapex"]`,
+ },
+ }
+ bpTemplate := `
+ cc_library {
+ name: "libfoo",
+ %v
+ apex_available: %v,
+ }
+ apex {
+ name: "myapex",
+ key: "apex.key",
+ updatable: false,
+ native_shared_libs: ["libfoo"],
+ }
+ apex {
+ name: "otherapex",
+ key: "apex.key",
+ updatable: false,
+ }
+ apex_test {
+ name: "test_myapex",
+ key: "apex.key",
+ updatable: false,
+ native_shared_libs: ["libfoo"],
+ }
+ apex_key {
+ name: "apex.key",
+ }
+ `
+ for _, tc := range testCases {
+ stubs := ""
+ if tc.hasStubs {
+ stubs = `stubs: {symbol_file: "libfoo.map.txt"},`
+ }
+ bp := fmt.Sprintf(bpTemplate, stubs, tc.apexAvailable)
+ mockFsFixturePreparer := android.FixtureModifyMockFS(func(fs android.MockFS) {
+ fs["system/sepolicy/apex/test_myapex-file_contexts"] = nil
+ })
+ if tc.expectedError == "" {
+ testApex(t, bp, mockFsFixturePreparer)
+ } else {
+ testApexError(t, tc.expectedError, bp, mockFsFixturePreparer)
+ }
+ }
+}
+
+func TestFileSystemShouldSkipApexLibraries(t *testing.T) {
+ context := android.GroupFixturePreparers(
+ android.PrepareForIntegrationTestWithAndroid,
+ cc.PrepareForIntegrationTestWithCc,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ filesystem.PrepareForTestWithFilesystemBuildComponents,
+ )
+ result := context.RunTestWithBp(t, `
+ android_system_image {
+ name: "myfilesystem",
+ deps: [
+ "libfoo",
+ ],
+ linker_config_src: "linker.config.json",
+ }
+
+ cc_library {
+ name: "libfoo",
+ shared_libs: [
+ "libbar",
+ ],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libbar",
+ stl: "none",
+ apex_available: ["myapex"],
+ }
+
+ apex {
+ name: "myapex",
+ native_shared_libs: ["libbar"],
+ key: "myapex.key",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+
+ inputs := result.ModuleForTests("myfilesystem", "android_common").Output("deps.zip").Implicits
+ android.AssertStringListDoesNotContain(t, "filesystem should not have libbar",
+ inputs.Strings(),
+ "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
+}
diff --git a/apex/bp2build_test.go b/apex/bp2build_test.go
index 2a0f6e9..b1b6a75 100644
--- a/apex/bp2build_test.go
+++ b/apex/bp2build_test.go
@@ -15,7 +15,10 @@
import (
"android/soong/android"
+ "android/soong/android/allowlists"
"android/soong/bazel/cquery"
+ "fmt"
+ "path/filepath"
"strings"
"testing"
)
@@ -326,7 +329,7 @@
}
func TestOverrideApexImageInMixedBuilds(t *testing.T) {
- bp := `
+ originalBp := `
apex_key{
name: "foo_key",
}
@@ -340,122 +343,203 @@
min_sdk_version: "31",
package_name: "pkg_name",
file_contexts: ":myapex-file_contexts",
- bazel_module: { label: "//:foo" },
-}
+ %s
+}`
+ overrideBp := `
override_apex {
name: "override_foo",
key: "override_foo_key",
package_name: "override_pkg_name",
base: "foo",
- bazel_module: { label: "//:override_foo" },
+ %s
}
`
- outputBaseDir := "out/bazel"
- result := android.GroupFixturePreparers(
- prepareForApexTest,
- android.FixtureModifyConfig(func(config android.Config) {
- config.BazelContext = android.MockBazelContext{
- OutputBaseDir: outputBaseDir,
- LabelToApexInfo: map[string]cquery.ApexInfo{
- "//:foo": cquery.ApexInfo{
- // ApexInfo Starlark provider
- SignedOutput: "signed_out.apex",
- UnsignedOutput: "unsigned_out.apex",
- BundleKeyInfo: []string{"public_key", "private_key"},
- ContainerKeyInfo: []string{"container_cert", "container_private"},
- SymbolsUsedByApex: "foo_using.txt",
- JavaSymbolsUsedByApex: "foo_using.xml",
- BundleFile: "apex_bundle.zip",
- InstalledFiles: "installed-files.txt",
- RequiresLibs: []string{"//path/c:c", "//path/d:d"},
+ originalApexBpDir := "original"
+ originalApexName := "foo"
+ overrideApexBpDir := "override"
+ overrideApexName := "override_foo"
- // unused
- PackageName: "pkg_name",
- ProvidesLibs: []string{"a", "b"},
+ defaultApexLabel := fmt.Sprintf("//%s:%s", originalApexBpDir, originalApexName)
+ defaultOverrideApexLabel := fmt.Sprintf("//%s:%s", overrideApexBpDir, overrideApexName)
- // ApexMkInfo Starlark provider
- MakeModulesToInstall: []string{"c"}, // d deliberately omitted
- },
- "//:override_foo": cquery.ApexInfo{
- // ApexInfo Starlark provider
- SignedOutput: "override_signed_out.apex",
- UnsignedOutput: "override_unsigned_out.apex",
- BundleKeyInfo: []string{"override_public_key", "override_private_key"},
- ContainerKeyInfo: []string{"override_container_cert", "override_container_private"},
- SymbolsUsedByApex: "override_foo_using.txt",
- JavaSymbolsUsedByApex: "override_foo_using.xml",
- BundleFile: "override_apex_bundle.zip",
- InstalledFiles: "override_installed-files.txt",
- RequiresLibs: []string{"//path/c:c", "//path/d:d"},
+ testCases := []struct {
+ desc string
+ bazelModuleProp string
+ apexLabel string
+ overrideBazelModuleProp string
+ overrideApexLabel string
+ bp2buildConfiguration android.Bp2BuildConversionAllowlist
+ }{
+ {
+ desc: "both explicit labels",
+ bazelModuleProp: `bazel_module: { label: "//:foo" },`,
+ apexLabel: "//:foo",
+ overrideBazelModuleProp: `bazel_module: { label: "//:override_foo" },`,
+ overrideApexLabel: "//:override_foo",
+ bp2buildConfiguration: android.NewBp2BuildAllowlist(),
+ },
+ {
+ desc: "both explicitly allowed",
+ bazelModuleProp: `bazel_module: { bp2build_available: true },`,
+ apexLabel: defaultApexLabel,
+ overrideBazelModuleProp: `bazel_module: { bp2build_available: true },`,
+ overrideApexLabel: defaultOverrideApexLabel,
+ bp2buildConfiguration: android.NewBp2BuildAllowlist(),
+ },
+ {
+ desc: "original allowed by dir, override allowed by name",
+ apexLabel: defaultApexLabel,
+ overrideApexLabel: defaultOverrideApexLabel,
+ bp2buildConfiguration: android.NewBp2BuildAllowlist().SetDefaultConfig(
+ map[string]allowlists.BazelConversionConfigEntry{
+ originalApexBpDir: allowlists.Bp2BuildDefaultTrue,
+ }).SetModuleAlwaysConvertList([]string{
+ overrideApexName,
+ }),
+ },
+ {
+ desc: "both allowed by name",
+ apexLabel: defaultApexLabel,
+ overrideApexLabel: defaultOverrideApexLabel,
+ bp2buildConfiguration: android.NewBp2BuildAllowlist().SetModuleAlwaysConvertList([]string{
+ originalApexName,
+ overrideApexName,
+ }),
+ },
+ {
+ desc: "override allowed by name",
+ apexLabel: defaultApexLabel,
+ overrideApexLabel: defaultOverrideApexLabel,
+ bp2buildConfiguration: android.NewBp2BuildAllowlist().SetModuleAlwaysConvertList([]string{
+ overrideApexName,
+ }),
+ },
+ {
+ desc: "override allowed by dir",
+ apexLabel: defaultApexLabel,
+ overrideApexLabel: defaultOverrideApexLabel,
+ bp2buildConfiguration: android.NewBp2BuildAllowlist().SetDefaultConfig(
+ map[string]allowlists.BazelConversionConfigEntry{
+ overrideApexBpDir: allowlists.Bp2BuildDefaultTrue,
+ }).SetModuleAlwaysConvertList([]string{}),
+ },
+ }
- // unused
- PackageName: "override_pkg_name",
- ProvidesLibs: []string{"a", "b"},
+ for _, tc := range testCases {
+ t.Run(tc.desc, func(t *testing.T) {
+ outputBaseDir := "out/bazel"
+ result := android.GroupFixturePreparers(
+ prepareForApexTest,
+ android.FixtureAddTextFile(filepath.Join(originalApexBpDir, "Android.bp"), fmt.Sprintf(originalBp, tc.bazelModuleProp)),
+ android.FixtureAddTextFile(filepath.Join(overrideApexBpDir, "Android.bp"), fmt.Sprintf(overrideBp, tc.overrideBazelModuleProp)),
+ android.FixtureModifyContext(func(ctx *android.TestContext) {
+ ctx.RegisterBp2BuildConfig(tc.bp2buildConfiguration)
+ }),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: outputBaseDir,
+ LabelToApexInfo: map[string]cquery.ApexInfo{
+ tc.apexLabel: cquery.ApexInfo{
+ // ApexInfo Starlark provider
+ SignedOutput: "signed_out.apex",
+ UnsignedOutput: "unsigned_out.apex",
+ BundleKeyInfo: []string{"public_key", "private_key"},
+ ContainerKeyInfo: []string{"container_cert", "container_private"},
+ SymbolsUsedByApex: "foo_using.txt",
+ JavaSymbolsUsedByApex: "foo_using.xml",
+ BundleFile: "apex_bundle.zip",
+ InstalledFiles: "installed-files.txt",
+ RequiresLibs: []string{"//path/c:c", "//path/d:d"},
- // ApexMkInfo Starlark provider
- MakeModulesToInstall: []string{"c"}, // d deliberately omitted
- },
- },
+ // unused
+ PackageName: "pkg_name",
+ ProvidesLibs: []string{"a", "b"},
+
+ // ApexMkInfo Starlark provider
+ MakeModulesToInstall: []string{"c"}, // d deliberately omitted
+ },
+ tc.overrideApexLabel: cquery.ApexInfo{
+ // ApexInfo Starlark provider
+ SignedOutput: "override_signed_out.apex",
+ UnsignedOutput: "override_unsigned_out.apex",
+ BundleKeyInfo: []string{"override_public_key", "override_private_key"},
+ ContainerKeyInfo: []string{"override_container_cert", "override_container_private"},
+ SymbolsUsedByApex: "override_foo_using.txt",
+ JavaSymbolsUsedByApex: "override_foo_using.xml",
+ BundleFile: "override_apex_bundle.zip",
+ InstalledFiles: "override_installed-files.txt",
+ RequiresLibs: []string{"//path/c:c", "//path/d:d"},
+
+ // unused
+ PackageName: "override_pkg_name",
+ ProvidesLibs: []string{"a", "b"},
+
+ // ApexMkInfo Starlark provider
+ MakeModulesToInstall: []string{"c"}, // d deliberately omitted
+ },
+ },
+ }
+ }),
+ ).RunTest(t)
+
+ m := result.ModuleForTests("foo", "android_common_override_foo_foo_image").Module()
+ ab, ok := m.(*apexBundle)
+ if !ok {
+ t.Fatalf("Expected module to be an apexBundle, was not")
}
- }),
- ).RunTestWithBp(t, bp)
- m := result.ModuleForTests("foo", "android_common_override_foo_foo_image").Module()
- ab, ok := m.(*apexBundle)
- if !ok {
- t.Fatalf("Expected module to be an apexBundle, was not")
- }
+ if w, g := "out/bazel/execroot/__main__/override_public_key", ab.publicKeyFile.String(); w != g {
+ t.Errorf("Expected public key %q, got %q", w, g)
+ }
- if w, g := "out/bazel/execroot/__main__/override_public_key", ab.publicKeyFile.String(); w != g {
- t.Errorf("Expected public key %q, got %q", w, g)
- }
+ if w, g := "out/bazel/execroot/__main__/override_private_key", ab.privateKeyFile.String(); w != g {
+ t.Errorf("Expected private key %q, got %q", w, g)
+ }
- if w, g := "out/bazel/execroot/__main__/override_private_key", ab.privateKeyFile.String(); w != g {
- t.Errorf("Expected private key %q, got %q", w, g)
- }
+ if w, g := "out/bazel/execroot/__main__/override_container_cert", ab.containerCertificateFile; g != nil && w != g.String() {
+ t.Errorf("Expected public container key %q, got %q", w, g)
+ }
- if w, g := "out/bazel/execroot/__main__/override_container_cert", ab.containerCertificateFile.String(); w != g {
- t.Errorf("Expected public container key %q, got %q", w, g)
- }
+ if w, g := "out/bazel/execroot/__main__/override_container_private", ab.containerPrivateKeyFile; g != nil && w != g.String() {
+ t.Errorf("Expected private container key %q, got %q", w, g)
+ }
- if w, g := "out/bazel/execroot/__main__/override_container_private", ab.containerPrivateKeyFile.String(); w != g {
- t.Errorf("Expected private container key %q, got %q", w, g)
- }
+ if w, g := "out/bazel/execroot/__main__/override_signed_out.apex", ab.outputFile.String(); w != g {
+ t.Errorf("Expected output file %q, got %q", w, g)
+ }
- if w, g := "out/bazel/execroot/__main__/override_signed_out.apex", ab.outputFile.String(); w != g {
- t.Errorf("Expected output file %q, got %q", w, g)
- }
+ if w, g := "out/bazel/execroot/__main__/override_foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
+ t.Errorf("Expected output file %q, got %q", w, g)
+ }
- if w, g := "out/bazel/execroot/__main__/override_foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
- t.Errorf("Expected output file %q, got %q", w, g)
- }
+ if w, g := "out/bazel/execroot/__main__/override_foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
+ t.Errorf("Expected output file %q, got %q", w, g)
+ }
- if w, g := "out/bazel/execroot/__main__/override_foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
- t.Errorf("Expected output file %q, got %q", w, g)
- }
+ if w, g := "out/bazel/execroot/__main__/override_installed-files.txt", ab.installedFilesFile.String(); w != g {
+ t.Errorf("Expected installed-files.txt %q, got %q", w, g)
+ }
- if w, g := "out/bazel/execroot/__main__/override_installed-files.txt", ab.installedFilesFile.String(); w != g {
- t.Errorf("Expected installed-files.txt %q, got %q", w, g)
- }
+ mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
+ var builder strings.Builder
+ mkData.Custom(&builder, "override_foo", "BAZEL_TARGET_", "", mkData)
- mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
- var builder strings.Builder
- mkData.Custom(&builder, "override_foo", "BAZEL_TARGET_", "", mkData)
+ data := builder.String()
+ if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/override_apex_bundle.zip"; !strings.Contains(data, w) {
+ t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
+ }
+ if w := "$(call dist-for-goals,checkbuild,out/bazel/execroot/__main__/override_installed-files.txt:override_foo-installed-files.txt)"; !strings.Contains(data, w) {
+ t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
+ }
- data := builder.String()
- if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/override_apex_bundle.zip"; !strings.Contains(data, w) {
- t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
- }
- if w := "$(call dist-for-goals,checkbuild,out/bazel/execroot/__main__/override_installed-files.txt:override_foo-installed-files.txt)"; !strings.Contains(data, w) {
- t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
- }
-
- // make modules to be installed to system
- if len(ab.makeModulesToInstall) != 1 && ab.makeModulesToInstall[0] != "c" {
- t.Errorf("Expected makeModulestoInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
- }
- if w := "LOCAL_REQUIRED_MODULES := c"; !strings.Contains(data, w) {
- t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
+ // make modules to be installed to system
+ if len(ab.makeModulesToInstall) != 1 || ab.makeModulesToInstall[0] != "c" {
+ t.Errorf("Expected makeModulestoInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
+ }
+ if w := "LOCAL_REQUIRED_MODULES := c"; !strings.Contains(data, w) {
+ t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
+ }
+ })
}
}
diff --git a/apex/builder.go b/apex/builder.go
index 3c7671b..7c6522d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -231,7 +231,7 @@
apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{
Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` +
- `&& ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
+ ` && ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
Description: "run apex_sepolicy_tests",
})
@@ -468,10 +468,6 @@
imageDir := android.PathForModuleOut(ctx, "image"+suffix)
installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable()
- // We can't install symbol files when prebuilt is used.
- if a.IsReplacedByPrebuilt() {
- installSymbolFiles = false
- }
// set of dependency module:location mappings
installMapSet := make(map[string]bool)
@@ -876,7 +872,8 @@
args["outCommaList"] = signedOutputFile.String()
}
var validations android.Paths
- if suffix == imageApexSuffix {
+ // TODO(b/279688635) deapexer supports [ext4]
+ if suffix == imageApexSuffix && ext4 == a.payloadFsType {
validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
}
ctx.Build(pctx, android.BuildParams{
diff --git a/apex/metadata.go b/apex/metadata.go
deleted file mode 100644
index b1dff3e..0000000
--- a/apex/metadata.go
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2023 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 apex
-
-import (
- "encoding/json"
-
- "github.com/google/blueprint"
-
- "android/soong/android"
-)
-
-var (
- mtctx = android.NewPackageContext("android/soong/multitree_apex")
-)
-
-func init() {
- RegisterModulesSingleton(android.InitRegistrationContext)
-}
-
-func RegisterModulesSingleton(ctx android.RegistrationContext) {
- ctx.RegisterSingletonType("apex_multitree_singleton", multitreeAnalysisSingletonFactory)
-}
-
-var PrepareForTestWithApexMultitreeSingleton = android.FixtureRegisterWithContext(RegisterModulesSingleton)
-
-func multitreeAnalysisSingletonFactory() android.Singleton {
- return &multitreeAnalysisSingleton{}
-}
-
-type multitreeAnalysisSingleton struct {
- multitreeApexMetadataPath android.OutputPath
-}
-
-type ApexMultitreeMetadataEntry struct {
- // The name of the apex.
- Name string
-
- // TODO: Add other properties as needed.
-}
-
-type ApexMultitreeMetadata struct {
- // Information about the installable apexes.
- Apexes map[string]ApexMultitreeMetadataEntry
-}
-
-func (p *multitreeAnalysisSingleton) GenerateBuildActions(context android.SingletonContext) {
- data := ApexMultitreeMetadata{
- Apexes: make(map[string]ApexMultitreeMetadataEntry, 0),
- }
- context.VisitAllModules(func(module android.Module) {
- // If this module is not being installed, ignore it.
- if !module.Enabled() || module.IsSkipInstall() {
- return
- }
- // Actual apexes provide ApexBundleInfoProvider.
- if _, ok := context.ModuleProvider(module, ApexBundleInfoProvider).(ApexBundleInfo); !ok {
- return
- }
- bundle, ok := module.(*apexBundle)
- if ok && !bundle.testApex && !bundle.vndkApex && bundle.primaryApexType {
- name := module.Name()
- entry := ApexMultitreeMetadataEntry{
- Name: name,
- }
- data.Apexes[name] = entry
- }
- })
- p.multitreeApexMetadataPath = android.PathForOutput(context, "multitree_apex_metadata.json")
-
- jsonStr, err := json.Marshal(data)
- if err != nil {
- context.Errorf(err.Error())
- }
- android.WriteFileRule(context, p.multitreeApexMetadataPath, string(jsonStr))
- // This seems cleaner, but doesn't emit the phony rule in testing.
- // context.Phony("multitree_apex_metadata", p.multitreeApexMetadataPath)
-
- context.Build(mtctx, android.BuildParams{
- Rule: blueprint.Phony,
- Description: "phony rule for multitree_apex_metadata",
- Inputs: []android.Path{p.multitreeApexMetadataPath},
- Output: android.PathForPhony(context, "multitree_apex_metadata"),
- })
-}
diff --git a/apex/metadata_test.go b/apex/metadata_test.go
deleted file mode 100644
index fed5bea..0000000
--- a/apex/metadata_test.go
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2023 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 apex
-
-import (
- "strings"
- "testing"
-
- "android/soong/android"
- "android/soong/java"
-)
-
-func TestModulesSingleton(t *testing.T) {
- result := android.GroupFixturePreparers(
- PrepareForTestWithApexMultitreeSingleton,
- java.PrepareForTestWithJavaDefaultModules,
- PrepareForTestWithApexBuildComponents,
- java.FixtureConfigureApexBootJars("myapex:foo"),
- java.PrepareForTestWithJavaSdkLibraryFiles,
- ).RunTestWithBp(t, `
- prebuilt_apex {
- name: "myapex",
- src: "myapex.apex",
- exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
- }
-
- // A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
- // because AlwaysUsePrebuiltSdks() is true.
- java_sdk_library_import {
- name: "foo",
- prefer: false,
- shared_library: false,
- permitted_packages: ["foo"],
- public: {
- jars: ["sdk_library/public/foo-stubs.jar"],
- stub_srcs: ["sdk_library/public/foo_stub_sources"],
- current_api: "sdk_library/public/foo.txt",
- removed_api: "sdk_library/public/foo-removed.txt",
- sdk_version: "current",
- },
- apex_available: ["myapex"],
- }
-
- prebuilt_bootclasspath_fragment {
- name: "mybootclasspath-fragment",
- apex_available: [
- "myapex",
- ],
- contents: [
- "foo",
- ],
- hidden_api: {
- stub_flags: "prebuilt-stub-flags.csv",
- annotation_flags: "prebuilt-annotation-flags.csv",
- metadata: "prebuilt-metadata.csv",
- index: "prebuilt-index.csv",
- all_flags: "prebuilt-all-flags.csv",
- },
- }
-
- platform_bootclasspath {
- name: "myplatform-bootclasspath",
- fragments: [
- {
- apex: "myapex",
- module:"mybootclasspath-fragment",
- },
- ],
- }
-`,
- )
-
- outputs := result.SingletonForTests("apex_multitree_singleton").AllOutputs()
- for _, output := range outputs {
- testingBuildParam := result.SingletonForTests("apex_multitree_singleton").Output(output)
- switch {
- case strings.Contains(output, "soong/multitree_apex_metadata.json"):
- android.AssertStringEquals(t, "Invalid build rule", "android/soong/android.writeFile", testingBuildParam.Rule.String())
- android.AssertIntEquals(t, "Invalid input", len(testingBuildParam.Inputs), 0)
- android.AssertStringDoesContain(t, "Invalid output path", output, "soong/multitree_apex_metadata.json")
-
- case strings.HasSuffix(output, "multitree_apex_metadata"):
- android.AssertStringEquals(t, "Invalid build rule", "<builtin>:phony", testingBuildParam.Rule.String())
- android.AssertStringEquals(t, "Invalid input", testingBuildParam.Inputs[0].String(), "out/soong/multitree_apex_metadata.json")
- android.AssertStringEquals(t, "Invalid output path", output, "multitree_apex_metadata")
- android.AssertIntEquals(t, "Invalid args", len(testingBuildParam.Args), 0)
- }
- }
-}
diff --git a/apex/testing.go b/apex/testing.go
index 69bd73e..3b200f0 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -19,6 +19,7 @@
var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers(
android.FixtureRegisterWithContext(registerApexBuildComponents),
android.FixtureRegisterWithContext(registerApexKeyBuildComponents),
+ android.FixtureRegisterWithContext(registerApexDepsInfoComponents),
// Additional files needed in tests that disallow non-existent source files.
// This includes files that are needed by all, or at least most, instances of an apex module type.
android.MockFS{
diff --git a/bazel/bazel_proxy.go b/bazel/bazel_proxy.go
index d7f5e64..2940b99 100644
--- a/bazel/bazel_proxy.go
+++ b/bazel/bazel_proxy.go
@@ -128,6 +128,24 @@
}
}
+func ExecBazel(bazelPath string, workspaceDir string, request CmdRequest) (stdout []byte, stderr []byte, cmdErr error) {
+ bazelCmd := exec.Command(bazelPath, request.Argv...)
+ bazelCmd.Dir = workspaceDir
+ bazelCmd.Env = request.Env
+
+ stderrBuffer := &bytes.Buffer{}
+ bazelCmd.Stderr = stderrBuffer
+
+ if output, err := bazelCmd.Output(); err != nil {
+ cmdErr = fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
+ err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderrBuffer)
+ } else {
+ stdout = output
+ }
+ stderr = stderrBuffer.Bytes()
+ return
+}
+
func (b *ProxyServer) handleRequest(conn net.Conn) error {
defer conn.Close()
@@ -137,23 +155,13 @@
return fmt.Errorf("Error decoding request: %s", err)
}
- bazelCmd := exec.Command("./build/bazel/bin/bazel", req.Argv...)
- bazelCmd.Dir = b.workspaceDir
- bazelCmd.Env = req.Env
-
- stderr := &bytes.Buffer{}
- bazelCmd.Stderr = stderr
- var stdout string
- var bazelErrString string
-
- if output, err := bazelCmd.Output(); err != nil {
- bazelErrString = fmt.Sprintf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
- err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
- } else {
- stdout = string(output)
+ stdout, stderr, cmdErr := ExecBazel("./build/bazel/bin/bazel", b.workspaceDir, req)
+ errorString := ""
+ if cmdErr != nil {
+ errorString = cmdErr.Error()
}
- resp := CmdResponse{stdout, string(stderr.Bytes()), bazelErrString}
+ resp := CmdResponse{string(stdout), string(stderr), errorString}
enc := gob.NewEncoder(conn)
if err := enc.Encode(&resp); err != nil {
return fmt.Errorf("Error encoding response: %s", err)
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 4680256..8f63ec4 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -31,11 +31,11 @@
// OsType names in arch.go
OsAndroid = "android"
- osDarwin = "darwin"
- osLinux = "linux_glibc"
+ OsDarwin = "darwin"
+ OsLinux = "linux_glibc"
osLinuxMusl = "linux_musl"
osLinuxBionic = "linux_bionic"
- osWindows = "windows"
+ OsWindows = "windows"
// Targets in arch.go
osArchAndroidArm = "android_arm"
@@ -69,8 +69,8 @@
productVariableBazelPackage = "//build/bazel/product_variables"
- AndroidAndInApex = "android-in_apex"
- AndroidAndNonApex = "android-non_apex"
+ AndroidAndInApex = "android-in_apex"
+ AndroidPlatform = "system"
InApex = "in_apex"
NonApex = "non_apex"
@@ -156,11 +156,11 @@
// constraint_value for the @platforms//os:os constraint_setting
platformOsMap = map[string]string{
OsAndroid: "//build/bazel/platforms/os:android",
- osDarwin: "//build/bazel/platforms/os:darwin",
- osLinux: "//build/bazel/platforms/os:linux_glibc",
+ OsDarwin: "//build/bazel/platforms/os:darwin",
+ OsLinux: "//build/bazel/platforms/os:linux_glibc",
osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
- osWindows: "//build/bazel/platforms/os:windows",
+ OsWindows: "//build/bazel/platforms/os:windows",
ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
@@ -192,22 +192,22 @@
// in a cyclic dependency.
osToArchMap = map[string][]string{
OsAndroid: {archArm, archArm64, archRiscv64, archX86, archX86_64},
- osLinux: {archX86, archX86_64},
+ OsLinux: {archX86, archX86_64},
osLinuxMusl: {archX86, archX86_64},
- osDarwin: {archArm64, archX86_64},
+ OsDarwin: {archArm64, archX86_64},
osLinuxBionic: {archArm64, archX86_64},
// TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
- osWindows: {archX86, archX86_64},
+ OsWindows: {archX86, archX86_64},
}
osAndInApexMap = map[string]string{
AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex",
- AndroidAndNonApex: "//build/bazel/rules/apex:android-non_apex",
- osDarwin: "//build/bazel/platforms/os:darwin",
- osLinux: "//build/bazel/platforms/os:linux_glibc",
+ AndroidPlatform: "//build/bazel/rules/apex:system",
+ OsDarwin: "//build/bazel/platforms/os:darwin",
+ OsLinux: "//build/bazel/platforms/os:linux_glibc",
osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
- osWindows: "//build/bazel/platforms/os:windows",
+ OsWindows: "//build/bazel/platforms/os:windows",
ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
}
@@ -268,9 +268,8 @@
case productVariables:
// do nothing
case osAndInApex:
- if _, ok := osAndInApexMap[config]; !ok {
- panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
- }
+ // do nothing
+ // this axis can contain additional per-apex keys
case inApex:
if _, ok := inApexMap[config]; !ok {
panic(fmt.Errorf("Unknown in_apex config: %s", config))
@@ -293,13 +292,15 @@
case osArch:
return platformOsArchMap[config]
case productVariables:
- if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
- // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
+ if config == ConditionsDefaultConfigKey {
return ConditionsDefaultSelectKey
}
return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
case osAndInApex:
- return osAndInApexMap[config]
+ if ret, exists := osAndInApexMap[config]; exists {
+ return ret
+ }
+ return config
case inApex:
return inApexMap[config]
default:
@@ -323,11 +324,11 @@
)
// ProductVariableConfigurationAxis returns an axis for the given product variable
-func ProductVariableConfigurationAxis(variable string, outerAxis ConfigurationAxis) ConfigurationAxis {
+func ProductVariableConfigurationAxis(archVariant bool, variable string) ConfigurationAxis {
return ConfigurationAxis{
configurationType: productVariables,
subType: variable,
- outerAxisType: outerAxis.configurationType,
+ archVariant: archVariant,
}
}
@@ -338,8 +339,8 @@
// some configuration types (e.g. productVariables) have multiple independent axes, subType helps
// distinguish between them without needing to list all 17 product variables.
subType string
- // used to keep track of which product variables are arch variant
- outerAxisType configurationType
+
+ archVariant bool
}
func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index bf3a6b5..6a3b3c8 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -149,6 +149,7 @@
rootSharedLibraries = []
shared_info_tag = "//build/bazel/rules/cc:cc_library_shared.bzl%CcSharedLibraryOutputInfo"
+stubs_tag = "//build/bazel/rules/cc:cc_stub_library.bzl%CcStubInfo"
unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
unstripped = ""
@@ -160,6 +161,8 @@
unstripped = path
if unstripped_tag in p:
unstripped = p[unstripped_tag].unstripped.path
+elif stubs_tag in p:
+ rootSharedLibraries.extend([f.path for f in target.files.to_list()])
else:
for linker_input in linker_inputs:
for library in linker_input.libraries:
diff --git a/bazel/properties.go b/bazel/properties.go
index 40d0ba3..e22f4db 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -334,7 +334,7 @@
if containsArch {
allProductVariablesAreArchVariant := true
for k := range la.ConfigurableValues {
- if k.configurationType == productVariables && k.outerAxisType != arch {
+ if k.configurationType == productVariables && !k.archVariant {
allProductVariablesAreArchVariant = false
}
}
@@ -1424,3 +1424,16 @@
sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
return sub, s != sub
}
+
+// StringMapAttribute is a map of strings.
+// The use case for this is storing the flag_values in a config_setting object.
+// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules.
+type StringMapAttribute map[string]string
+
+// ConfigSettingAttributes stores the keys of a config_setting object.
+type ConfigSettingAttributes struct {
+ // Each key in Flag_values is a label to a custom string_setting
+ Flag_values StringMapAttribute
+ // Each element in Constraint_values is a label to a constraint_value
+ Constraint_values LabelListAttribute
+}
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index cf03eb5..c56d11f 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -248,13 +248,13 @@
OsArchConfigurationAxis: labelListSelectValues{
"linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
},
- ProductVariableConfigurationAxis("product_with_defaults", NoConfigAxis): labelListSelectValues{
+ ProductVariableConfigurationAxis(false, "product_with_defaults"): labelListSelectValues{
"a": makeLabelList([]string{}, []string{"not_in_value"}),
"b": makeLabelList([]string{"b_val"}, []string{}),
"c": makeLabelList([]string{"c_val"}, []string{}),
ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2", "all_exclude"}, []string{}),
},
- ProductVariableConfigurationAxis("product_only_with_excludes", NoConfigAxis): labelListSelectValues{
+ ProductVariableConfigurationAxis(false, "product_only_with_excludes"): labelListSelectValues{
"a": makeLabelList([]string{}, []string{"product_config_exclude"}),
},
},
@@ -282,13 +282,13 @@
"linux_x86": makeLabels("linux_x86_include"),
ConditionsDefaultConfigKey: nilLabels,
},
- ProductVariableConfigurationAxis("product_with_defaults", NoConfigAxis): {
+ ProductVariableConfigurationAxis(false, "product_with_defaults"): {
"a": nilLabels,
"b": makeLabels("b_val"),
"c": makeLabels("c_val"),
ConditionsDefaultConfigKey: makeLabels("c_val", "default", "default2"),
},
- ProductVariableConfigurationAxis("product_only_with_excludes", NoConfigAxis): {
+ ProductVariableConfigurationAxis(false, "product_only_with_excludes"): {
"a": nilLabels,
ConditionsDefaultConfigKey: makeLabels("product_config_exclude"),
},
@@ -679,7 +679,7 @@
OsArchConfigurationAxis: stringListSelectValues{
"linux_x86": {"linux_x86_include"},
},
- ProductVariableConfigurationAxis("a", NoConfigAxis): stringListSelectValues{
+ ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
"a": []string{"not_in_value"},
},
},
@@ -704,7 +704,7 @@
"linux": []string{"linux_include"},
},
OsArchConfigurationAxis: stringListSelectValues{},
- ProductVariableConfigurationAxis("a", NoConfigAxis): stringListSelectValues{
+ ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
"a": []string{"not_in_value"},
},
}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index b6635c4..9ec3a40 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -19,6 +19,7 @@
"testing.go",
],
deps: [
+ "soong-aidl-library",
"soong-android",
"soong-android-allowlists",
"soong-android-soongconfig",
@@ -37,6 +38,7 @@
],
testSrcs: [
"aar_conversion_test.go",
+ "aidl_library_conversion_test.go",
"android_app_certificate_conversion_test.go",
"android_app_conversion_test.go",
"apex_conversion_test.go",
diff --git a/bp2build/aidl_library_conversion_test.go b/bp2build/aidl_library_conversion_test.go
new file mode 100644
index 0000000..0522da4
--- /dev/null
+++ b/bp2build/aidl_library_conversion_test.go
@@ -0,0 +1,119 @@
+// Copyright 2023 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 bp2build
+
+import (
+ "testing"
+
+ "android/soong/aidl_library"
+ "android/soong/android"
+)
+
+func runAidlLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
+ t.Helper()
+ (&tc).ModuleTypeUnderTest = "aidl_library"
+ (&tc).ModuleTypeUnderTestFactory = aidl_library.AidlLibraryFactory
+ RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+func TestAidlLibrary(t *testing.T) {
+ testcases := []struct {
+ name string
+ bp string
+ expectedBazelAttrs AttrNameToString
+ }{
+ {
+ name: "aidl_library with strip_import_prefix",
+ bp: `
+ aidl_library {
+ name: "foo",
+ srcs: ["aidl/foo.aidl"],
+ hdrs: ["aidl/header.aidl"],
+ strip_import_prefix: "aidl",
+ }`,
+ expectedBazelAttrs: AttrNameToString{
+ "srcs": `["aidl/foo.aidl"]`,
+ "hdrs": `["aidl/header.aidl"]`,
+ "strip_import_prefix": `"aidl"`,
+ "tags": `["apex_available=//apex_available:anyapex"]`,
+ },
+ },
+ {
+ name: "aidl_library without strip_import_prefix",
+ bp: `
+ aidl_library {
+ name: "foo",
+ srcs: ["aidl/foo.aidl"],
+ hdrs: ["aidl/header.aidl"],
+ }`,
+ expectedBazelAttrs: AttrNameToString{
+ "srcs": `["aidl/foo.aidl"]`,
+ "hdrs": `["aidl/header.aidl"]`,
+ "tags": `["apex_available=//apex_available:anyapex"]`,
+ },
+ },
+ }
+
+ for _, test := range testcases {
+ t.Run(test.name, func(t *testing.T) {
+ expectedBazelTargets := []string{
+ MakeBazelTargetNoRestrictions("aidl_library", "foo", test.expectedBazelAttrs),
+ }
+ runAidlLibraryTestCase(t, Bp2buildTestCase{
+ Description: test.name,
+ Blueprint: test.bp,
+ ExpectedBazelTargets: expectedBazelTargets,
+ })
+ })
+ }
+}
+
+func TestAidlLibraryWithDeps(t *testing.T) {
+ bp := `
+ aidl_library {
+ name: "bar",
+ srcs: ["Bar.aidl"],
+ hdrs: ["aidl/BarHeader.aidl"],
+ }
+ aidl_library {
+ name: "foo",
+ srcs: ["aidl/Foo.aidl"],
+ hdrs: ["aidl/FooHeader.aidl"],
+ strip_import_prefix: "aidl",
+ deps: ["bar"],
+ }`
+
+ t.Run("aidl_library with deps", func(t *testing.T) {
+ expectedBazelTargets := []string{
+ MakeBazelTargetNoRestrictions("aidl_library", "bar", AttrNameToString{
+ "srcs": `["Bar.aidl"]`,
+ "hdrs": `["aidl/BarHeader.aidl"]`,
+ "tags": `["apex_available=//apex_available:anyapex"]`,
+ }),
+ MakeBazelTargetNoRestrictions("aidl_library", "foo", AttrNameToString{
+ "srcs": `["aidl/Foo.aidl"]`,
+ "hdrs": `["aidl/FooHeader.aidl"]`,
+ "strip_import_prefix": `"aidl"`,
+ "deps": `[":bar"]`,
+ "tags": `["apex_available=//apex_available:anyapex"]`,
+ }),
+ }
+ runAidlLibraryTestCase(t, Bp2buildTestCase{
+ Description: "aidl_library with deps",
+ Blueprint: bp,
+ ExpectedBazelTargets: expectedBazelTargets,
+ })
+ })
+}
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index 928a1f2..7f7aa6a 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -80,6 +80,7 @@
static_libs: ["static_lib_dep"],
java_version: "7",
certificate: "foocert",
+ required: ["static_lib_dep"],
}
`,
ExpectedBazelTargets: []string{
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 1cc3f22..390cabe 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -1475,10 +1475,11 @@
`,
ExpectedBazelTargets: []string{
MakeBazelTarget("apex", "test_com.android.apogee", AttrNameToString{
- "file_contexts": `"file_contexts_file"`,
- "manifest": `"apex_manifest.json"`,
- "testonly": `True`,
- "tests": `[":cc_test_1"]`,
+ "file_contexts": `"file_contexts_file"`,
+ "base_apex_name": `"com.android.apogee"`,
+ "manifest": `"apex_manifest.json"`,
+ "testonly": `True`,
+ "tests": `[":cc_test_1"]`,
}),
}})
}
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index d1dfb9d..b22cb28 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -15,6 +15,7 @@
package bp2build
import (
+ "android/soong/starlark_import"
"fmt"
"os"
"path/filepath"
@@ -93,6 +94,12 @@
os.Exit(1)
}
writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
+ starlarkDeps, err := starlark_import.GetNinjaDeps()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ os.Exit(1)
+ }
+ ctx.AddNinjaFileDeps(starlarkDeps...)
return &res.metrics
}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index b7678a4..a860484 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -600,6 +600,11 @@
// TODO(b/164227191): implement pretty print for interfaces.
// Interfaces are used for for arch, multilib and target properties.
return "", nil
+ case reflect.Map:
+ if v, ok := propertyValue.Interface().(bazel.StringMapAttribute); ok {
+ return starlark_fmt.PrintStringStringDict(v, indent), nil
+ }
+ return "", fmt.Errorf("bp2build expects map of type map[string]string for field: %s", propertyValue)
default:
return "", fmt.Errorf(
"unexpected kind for property struct field: %s", propertyValue.Kind())
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 73ee26b..e127fd5 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -21,6 +21,7 @@
"android/soong/android"
"android/soong/android/allowlists"
+ "android/soong/bazel"
"android/soong/python"
)
@@ -1898,3 +1899,50 @@
Description: "Generating API contribution Bazel targets for custom module",
})
}
+
+func TestGenerateConfigSetting(t *testing.T) {
+ bp := `
+ custom {
+ name: "foo",
+ test_config_setting: true,
+ }
+ `
+ expectedBazelTargets := []string{
+ MakeBazelTargetNoRestrictions(
+ "config_setting",
+ "foo_config_setting",
+ AttrNameToString{
+ "flag_values": `{
+ "//build/bazel/rules/my_string_setting": "foo",
+ }`,
+ },
+ ),
+ MakeBazelTarget(
+ "custom",
+ "foo",
+ AttrNameToString{},
+ ),
+ }
+ registerCustomModule := func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+ }
+ RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+ Blueprint: bp,
+ ExpectedBazelTargets: expectedBazelTargets,
+ Description: "Generating API contribution Bazel targets for custom module",
+ })
+}
+
+// If values of all keys in an axis are equal to //conditions:default, drop the axis and print the common value
+func TestPrettyPrintSelectMapEqualValues(t *testing.T) {
+ lla := bazel.LabelListAttribute{
+ Value: bazel.LabelList{},
+ }
+ libFooImplLabel := bazel.Label{
+ Label: ":libfoo.impl",
+ }
+ lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList([]bazel.Label{libFooImplLabel}))
+ lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{libFooImplLabel}))
+ actual, _ := prettyPrintAttribute(lla, 0)
+ android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual)
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index a8e557d..fa1bf8a 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -108,6 +108,7 @@
"string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
+ "test_config_setting": attr.bool(),
},
)
@@ -139,6 +140,7 @@
"string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
+ "test_config_setting": attr.bool(),
},
)
@@ -170,6 +172,7 @@
"string_literal_prop": attr.string(),
"string_prop": attr.string(),
"string_ptr_prop": attr.string(),
+ "test_config_setting": attr.bool(),
# test_prop start
# "test_string_prop": attr.string(),
# test_prop end
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index 0315732..6ec3703 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -644,10 +644,7 @@
targets: []testBazelTarget{
{"cc_binary", "foo", AttrNameToString{
"features": `select({
- "//build/bazel/platforms/arch:arm": [
- "arm_isa_arm",
- "-arm_isa_thumb",
- ],
+ "//build/bazel/platforms/arch:arm": ["arm_isa_arm"],
"//conditions:default": [],
})`,
"local_includes": `["."]`,
@@ -996,3 +993,44 @@
},
})
}
+
+func TestCcBinaryHiddenVisibilityConvertedToFeature(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary changes hidden visibility to feature",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ cflags: ["-fvisibility=hidden"],
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `["visibility_hidden"]`,
+ }},
+ },
+ })
+}
+
+func TestCcBinaryHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+ runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
+ description: "cc_binary changes hidden visibility to feature for specific os",
+ blueprint: `
+{rule_name} {
+ name: "foo",
+ target: {
+ android: {
+ cflags: ["-fvisibility=hidden"],
+ },
+ },
+}`,
+ targets: []testBazelTarget{
+ {"cc_binary", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ }},
+ },
+ })
+}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index d2c463d..0e8705b 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -18,6 +18,7 @@
"fmt"
"testing"
+ "android/soong/aidl_library"
"android/soong/android"
"android/soong/cc"
)
@@ -63,6 +64,7 @@
ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory)
ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+ ctx.RegisterModuleType("aidl_library", aidl_library.AidlLibraryFactory)
}
func TestCcLibrarySimple(t *testing.T) {
@@ -153,10 +155,10 @@
"//build/bazel/platforms/os:linux_glibc": ["linux.cpp"],
"//conditions:default": [],
})`,
- "sdk_version": `"current"`,
- "min_sdk_version": `"29"`,
- "use_version_lib": `True`,
- "implementation_whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
+ "sdk_version": `"current"`,
+ "min_sdk_version": `"29"`,
+ "use_version_lib": `True`,
+ "whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
}),
})
}
@@ -3042,7 +3044,8 @@
}`,
ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
"implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
+ "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:barlib"],
+ "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:barlib"],
"//conditions:default": [":barlib"],
})`,
"local_includes": `["."]`,
@@ -3096,7 +3099,11 @@
"//build/bazel/platforms/os:linux_glibc": [":quxlib"],
"//build/bazel/platforms/os:linux_musl": [":quxlib"],
"//build/bazel/platforms/os:windows": [":quxlib"],
- "//build/bazel/rules/apex:android-in_apex": [
+ "//build/bazel/rules/apex:foo": [
+ "@api_surfaces//module-libapi/current:barlib",
+ "@api_surfaces//module-libapi/current:quxlib",
+ ],
+ "//build/bazel/rules/apex:system": [
"@api_surfaces//module-libapi/current:barlib",
"@api_surfaces//module-libapi/current:quxlib",
],
@@ -3214,10 +3221,7 @@
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
"features": `select({
- "//build/bazel/platforms/arch:arm": [
- "arm_isa_arm",
- "-arm_isa_thumb",
- ],
+ "//build/bazel/platforms/arch:arm": ["arm_isa_arm"],
"//conditions:default": [],
})`,
"local_includes": `["."]`,
@@ -3310,6 +3314,51 @@
})
}
+func TestCcLibraryWithAidlLibrary(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library with aidl_library",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+aidl_library {
+ name: "A_aidl",
+ srcs: ["aidl/A.aidl"],
+ hdrs: ["aidl/Header.aidl"],
+ strip_import_prefix: "aidl",
+}
+cc_library {
+ name: "foo",
+ aidl: {
+ libs: ["A_aidl"],
+ },
+ export_include_dirs: ["include"],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("aidl_library", "A_aidl", AttrNameToString{
+ "srcs": `["aidl/A.aidl"]`,
+ "hdrs": `["aidl/Header.aidl"]`,
+ "strip_import_prefix": `"aidl"`,
+ "tags": `["apex_available=//apex_available:anyapex"]`,
+ }),
+ MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
+ "deps": `[":A_aidl"]`,
+ "local_includes": `["."]`,
+ "export_includes": `["include"]`,
+ }),
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
+ "local_includes": `["."]`,
+ "export_includes": `["include"]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
+ "local_includes": `["."]`,
+ "export_includes": `["include"]`,
+ }),
+ },
+ })
+}
+
func TestCcLibraryWithAidlSrcs(t *testing.T) {
runCcLibraryTestCase(t, Bp2buildTestCase{
Description: "cc_library with aidl srcs",
@@ -3338,6 +3387,7 @@
"srcs": `["B.aidl"]`,
}),
MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
+ "local_includes": `["."]`,
"deps": `[
":A_aidl",
":foo_aidl_library",
@@ -3377,7 +3427,8 @@
}`,
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
- "deps": `["//path/to/A:A_aidl"]`,
+ "local_includes": `["."]`,
+ "deps": `["//path/to/A:A_aidl"]`,
}),
MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
@@ -3392,37 +3443,78 @@
}
func TestCcLibraryWithExportAidlHeaders(t *testing.T) {
- runCcLibraryTestCase(t, Bp2buildTestCase{
- Description: "cc_library with export aidl headers",
- ModuleTypeUnderTest: "cc_library",
- ModuleTypeUnderTestFactory: cc.LibraryFactory,
- Blueprint: `
-cc_library {
- name: "foo",
- srcs: [
- "Foo.aidl",
- ],
- aidl: {
- export_aidl_headers: true,
- }
-}`,
- ExpectedBazelTargets: []string{
- MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
- "srcs": `["Foo.aidl"]`,
- }),
- MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
- "deps": `[":foo_aidl_library"]`,
- }),
- MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
- "whole_archive_deps": `[":foo_cc_aidl_library"]`,
- "local_includes": `["."]`,
- }),
- MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
- "whole_archive_deps": `[":foo_cc_aidl_library"]`,
- "local_includes": `["."]`,
- }),
+ t.Parallel()
+
+ expectedBazelTargets := []string{
+ MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
+ "local_includes": `["."]`,
+ "deps": `[":foo_aidl_library"]`,
+ }),
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "whole_archive_deps": `[":foo_cc_aidl_library"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "whole_archive_deps": `[":foo_cc_aidl_library"]`,
+ "local_includes": `["."]`,
+ }),
+ }
+ testCases := []struct {
+ description string
+ bp string
+ expectedBazelTargets []string
+ }{
+ {
+ description: "cc_library with aidl srcs and aidl.export_aidl_headers set",
+ bp: `
+ cc_library {
+ name: "foo",
+ srcs: [
+ "Foo.aidl",
+ ],
+ aidl: {
+ export_aidl_headers: true,
+ }
+ }`,
+ expectedBazelTargets: append(
+ expectedBazelTargets,
+ MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
+ "srcs": `["Foo.aidl"]`,
+ })),
},
- })
+ {
+ description: "cc_library with aidl.libs and aidl.export_aidl_headers set",
+ bp: `
+ aidl_library {
+ name: "foo_aidl_library",
+ srcs: ["Foo.aidl"],
+ }
+ cc_library {
+ name: "foo",
+ aidl: {
+ libs: ["foo_aidl_library"],
+ export_aidl_headers: true,
+ }
+ }`,
+ expectedBazelTargets: append(
+ expectedBazelTargets,
+ MakeBazelTargetNoRestrictions("aidl_library", "foo_aidl_library", AttrNameToString{
+ "srcs": `["Foo.aidl"]`,
+ "tags": `["apex_available=//apex_available:anyapex"]`,
+ }),
+ ),
+ },
+ }
+
+ for _, testCase := range testCases {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library with export aidl headers",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: testCase.bp,
+ ExpectedBazelTargets: testCase.expectedBazelTargets,
+ })
+ }
}
func TestCcLibraryWithTargetApex(t *testing.T) {
@@ -3637,7 +3729,8 @@
"srcs": `["Foo.aidl"]`,
}),
MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
- "deps": `[":foo_aidl_library"]`,
+ "local_includes": `["."]`,
+ "deps": `[":foo_aidl_library"]`,
"implementation_deps": `[
":baz-static",
":bar-static",
@@ -4139,44 +4232,34 @@
name: "barlib",
stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
bazel_module: { bp2build_available: false },
+ apex_available: ["//apex_available:platform",],
}
cc_library {
name: "bazlib",
stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
bazel_module: { bp2build_available: false },
+ apex_available: ["//apex_available:platform",],
}
cc_library {
name: "foo",
shared_libs: ["barlib", "bazlib"],
export_shared_lib_headers: ["bazlib"],
apex_available: [
- "apex_available:platform",
+ "//apex_available:platform",
],
}`,
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
- "implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
- "//conditions:default": [":barlib"],
- })`,
- "dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
- "//conditions:default": [":bazlib"],
- })`,
- "local_includes": `["."]`,
- "tags": `["apex_available=apex_available:platform"]`,
+ "implementation_dynamic_deps": `[":barlib"]`,
+ "dynamic_deps": `[":bazlib"]`,
+ "local_includes": `["."]`,
+ "tags": `["apex_available=//apex_available:platform"]`,
}),
MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
- "implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
- "//conditions:default": [":barlib"],
- })`,
- "dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
- "//conditions:default": [":bazlib"],
- })`,
- "local_includes": `["."]`,
- "tags": `["apex_available=apex_available:platform"]`,
+ "implementation_dynamic_deps": `[":barlib"]`,
+ "dynamic_deps": `[":bazlib"]`,
+ "local_includes": `["."]`,
+ "tags": `["apex_available=//apex_available:platform"]`,
}),
},
})
@@ -4350,3 +4433,279 @@
},
})
}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeature(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library changes hidden visibility flag to feature",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ cflags: ["-fvisibility=hidden"],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureSharedSpecific(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library changes hidden visibility flag to feature when specific to shared variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ shared: {
+ cflags: ["-fvisibility=hidden"],
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureStaticSpecific(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library changes hidden visibility flag to feature when specific to static variant",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ static: {
+ cflags: ["-fvisibility=hidden"],
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library changes hidden visibility flag to feature when specific to an os",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: `
+cc_library {
+ name: "foo",
+ target: {
+ android: {
+ cflags: ["-fvisibility=hidden"],
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+// Test that a config_setting specific to an apex is created by cc_library.
+func TestCcLibraryCreatesInApexConfigSetting(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library creates a config_setting for each apex in apex_available",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Dir: "build/bazel/rules/apex",
+ Blueprint: `
+cc_library {
+ name: "foo",
+ apex_available: [
+ "//apex_available:platform", // This will be skipped, since it is equivalent to //build/bazel/rules/apex:android-non_apex
+ "myapex"
+ ],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions(
+ "config_setting",
+ "myapex",
+ AttrNameToString{
+ "flag_values": `{
+ "//build/bazel/rules/apex:api_domain": "myapex",
+ }`,
+ "constraint_values": `["//build/bazel/platforms/os:android"]`,
+ },
+ ),
+ },
+ })
+}
+
+func TestCcLibraryCppFlagsInProductVariables(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library cppflags in product variables",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `cc_library {
+ name: "a",
+ srcs: ["a.cpp"],
+ cppflags: [
+ "-Wextra",
+ "-DDEBUG_ONLY_CODE=0",
+ ],
+ product_variables: {
+ eng: {
+ cppflags: [
+ "-UDEBUG_ONLY_CODE",
+ "-DDEBUG_ONLY_CODE=1",
+ ],
+ },
+ },
+ include_build_directory: false,
+}
+`,
+ ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
+ "cppflags": `[
+ "-Wextra",
+ "-DDEBUG_ONLY_CODE=0",
+ ] + select({
+ "//build/bazel/product_variables:eng": [
+ "-UDEBUG_ONLY_CODE",
+ "-DDEBUG_ONLY_CODE=1",
+ ],
+ "//conditions:default": [],
+ })`,
+ "srcs": `["a.cpp"]`,
+ }),
+ },
+ )
+}
+
+func TestCcLibraryYaccConversion(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_library is built from .y/.yy files",
+ ModuleTypeUnderTest: "cc_library",
+ ModuleTypeUnderTestFactory: cc.LibraryFactory,
+ Blueprint: soongCcLibraryPreamble + `cc_library {
+ name: "a",
+ srcs: [
+ "a.cpp",
+ "a.yy",
+ ],
+ shared_libs: ["sharedlib"],
+ static_libs: ["staticlib"],
+ yacc: {
+ flags: ["someYaccFlag"],
+ gen_location_hh: true,
+ gen_position_hh: true,
+ },
+}
+cc_library_static {
+ name: "staticlib",
+ bazel_module: { bp2build_available: false },
+}
+cc_library {
+ name: "sharedlib",
+ bazel_module: { bp2build_available: false },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_yacc_static_library", "a_yacc", AttrNameToString{
+ "src": `"a.yy"`,
+ "implementation_deps": `[":staticlib"]`,
+ "implementation_dynamic_deps": `[":sharedlib"]`,
+ "flags": `["someYaccFlag"]`,
+ "gen_location_hh": "True",
+ "gen_position_hh": "True",
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
+ "srcs": `["a.cpp"]`,
+ "implementation_deps": `[":staticlib"]`,
+ "implementation_dynamic_deps": `[":sharedlib"]`,
+ "implementation_whole_archive_deps": `[":a_yacc"]`,
+ "local_includes": `["."]`,
+ }),
+ MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
+ "srcs": `["a.cpp"]`,
+ "implementation_deps": `[":staticlib"]`,
+ "implementation_dynamic_deps": `[":sharedlib"]`,
+ "implementation_whole_archive_deps": `[":a_yacc"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryHostLdLibs(t *testing.T) {
+ runCcLibraryTestCase(t, Bp2buildTestCase{
+ Description: "cc_binary linker flags for host_ldlibs",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: soongCcLibraryPreamble + `cc_binary {
+ name: "a",
+ host_supported: true,
+ ldflags: ["-lcommon"],
+ target: {
+ linux: {
+ host_ldlibs: [
+ "-llinux",
+ ],
+ },
+ darwin: {
+ ldflags: ["-ldarwinadditional"],
+ host_ldlibs: [
+ "-ldarwin",
+ ],
+ },
+ windows: {
+ host_ldlibs: [
+ "-lwindows",
+ ],
+ },
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTargetNoRestrictions("cc_binary", "a", AttrNameToString{
+ "linkopts": `["-lcommon"] + select({
+ "//build/bazel/platforms/os:darwin": [
+ "-ldarwinadditional",
+ "-ldarwin",
+ ],
+ "//build/bazel/platforms/os:linux_glibc": ["-llinux"],
+ "//build/bazel/platforms/os:windows": ["-lwindows"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index cbea943..2ee9c99 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -516,8 +516,8 @@
}`,
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
- "use_version_lib": "True",
- "implementation_whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
+ "use_version_lib": "True",
+ "whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
}),
},
})
@@ -609,7 +609,8 @@
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
"implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"],
+ "//build/bazel/rules/apex:apex_b": ["@api_surfaces//module-libapi/current:a"],
+ "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
"//conditions:default": [":a"],
})`,
"tags": `["apex_available=apex_b"]`,
@@ -618,6 +619,64 @@
})
}
+// Tests that library in apexfoo links against stubs of platform_lib and otherapex_lib
+func TestCcLibrarySharedStubs_UseStubsFromMultipleApiDomains(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared stubs",
+ ModuleTypeUnderTest: "cc_library_shared",
+ ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ Blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+ name: "libplatform_stable",
+ stubs: { symbol_file: "libplatform_stable.map.txt", versions: ["28", "29", "current"] },
+ apex_available: ["//apex_available:platform"],
+ bazel_module: { bp2build_available: false },
+ include_build_directory: false,
+}
+cc_library_shared {
+ name: "libapexfoo_stable",
+ stubs: { symbol_file: "libapexfoo_stable.map.txt", versions: ["28", "29", "current"] },
+ apex_available: ["apexfoo"],
+ bazel_module: { bp2build_available: false },
+ include_build_directory: false,
+}
+cc_library_shared {
+ name: "libutils",
+ shared_libs: ["libplatform_stable", "libapexfoo_stable",],
+ apex_available: ["//apex_available:platform", "apexfoo", "apexbar"],
+ include_build_directory: false,
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "libutils", AttrNameToString{
+ "implementation_dynamic_deps": `select({
+ "//build/bazel/rules/apex:apexbar": [
+ "@api_surfaces//module-libapi/current:libplatform_stable",
+ "@api_surfaces//module-libapi/current:libapexfoo_stable",
+ ],
+ "//build/bazel/rules/apex:apexfoo": [
+ "@api_surfaces//module-libapi/current:libplatform_stable",
+ ":libapexfoo_stable",
+ ],
+ "//build/bazel/rules/apex:system": [
+ "@api_surfaces//module-libapi/current:libplatform_stable",
+ "@api_surfaces//module-libapi/current:libapexfoo_stable",
+ ],
+ "//conditions:default": [
+ ":libplatform_stable",
+ ":libapexfoo_stable",
+ ],
+ })`,
+ "tags": `[
+ "apex_available=//apex_available:platform",
+ "apex_available=apexfoo",
+ "apex_available=apexbar",
+ ]`,
+ }),
+ },
+ })
+}
+
func TestCcLibrarySharedStubs_IgnorePlatformAvailable(t *testing.T) {
runCcLibrarySharedTestCase(t, Bp2buildTestCase{
Description: "cc_library_shared stubs",
@@ -641,7 +700,8 @@
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
"implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"],
+ "//build/bazel/rules/apex:apex_b": ["@api_surfaces//module-libapi/current:a"],
+ "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
"//conditions:default": [":a"],
})`,
"tags": `[
@@ -653,6 +713,34 @@
})
}
+func TestCcLibraryDoesNotDropStubDepIfNoVariationAcrossAxis(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library depeends on impl for all configurations",
+ ModuleTypeUnderTest: "cc_library_shared",
+ ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ Blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+ name: "a",
+ stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
+ bazel_module: { bp2build_available: false },
+ apex_available: ["//apex_available:platform"],
+}
+cc_library_shared {
+ name: "b",
+ shared_libs: [":a"],
+ include_build_directory: false,
+ apex_available: ["//apex_available:platform"],
+}
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
+ "implementation_dynamic_deps": `[":a"]`,
+ "tags": `["apex_available=//apex_available:platform"]`,
+ }),
+ },
+ })
+}
+
func TestCcLibrarySharedStubs_MultipleApexAvailable(t *testing.T) {
runCcLibrarySharedTestCase(t, Bp2buildTestCase{
ModuleTypeUnderTest: "cc_library_shared",
@@ -682,7 +770,7 @@
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
"implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:a"],
+ "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
"//conditions:default": [":a"],
})`,
"tags": `[
@@ -1250,3 +1338,107 @@
},
})
}
+
+func TestCcLibrarySharedHiddenVisibilityConvertedToFeature(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared changes hidden visibility flag to feature",
+ Blueprint: `
+cc_library_shared{
+ name: "foo",
+ cflags: ["-fvisibility=hidden"],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared changes hidden visibility flag to feature for specific os",
+ Blueprint: `
+cc_library_shared{
+ name: "foo",
+ target: {
+ android: {
+ cflags: ["-fvisibility=hidden"],
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibrarySharedStubsDessertVersionConversion(t *testing.T) {
+ runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_shared converts dessert codename versions to numerical versions",
+ Blueprint: `
+cc_library_shared {
+ name: "a",
+ include_build_directory: false,
+ stubs: {
+ symbol_file: "a.map.txt",
+ versions: [
+ "Q",
+ "R",
+ "31",
+ ],
+ },
+}
+cc_library_shared {
+ name: "b",
+ include_build_directory: false,
+ stubs: {
+ symbol_file: "b.map.txt",
+ versions: [
+ "Q",
+ "R",
+ "31",
+ "current",
+ ],
+ },
+}
+`,
+ ExpectedBazelTargets: []string{
+ makeCcStubSuiteTargets("a", AttrNameToString{
+ "soname": `"a.so"`,
+ "source_library_label": `"//:a"`,
+ "stubs_symbol_file": `"a.map.txt"`,
+ "stubs_versions": `[
+ "29",
+ "30",
+ "31",
+ "current",
+ ]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
+ "stubs_symbol_file": `"a.map.txt"`,
+ }),
+ makeCcStubSuiteTargets("b", AttrNameToString{
+ "soname": `"b.so"`,
+ "source_library_label": `"//:b"`,
+ "stubs_symbol_file": `"b.map.txt"`,
+ "stubs_versions": `[
+ "29",
+ "30",
+ "31",
+ "current",
+ ]`,
+ }),
+ MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
+ "stubs_symbol_file": `"b.map.txt"`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index cd4cf51..2705aaf 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1504,6 +1504,7 @@
versions: ["current"],
},
bazel_module: { bp2build_available: false },
+ apex_available: ["com.android.runtime"],
}
cc_library_static {
@@ -1561,7 +1562,8 @@
}),
MakeBazelTarget("cc_library_static", "keep_with_stubs", AttrNameToString{
"implementation_dynamic_deps": `select({
- "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:libm"],
+ "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:libm"],
+ "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:libm"],
"//conditions:default": [":libm"],
})`,
"system_dynamic_deps": `[]`,
@@ -1613,7 +1615,7 @@
}`,
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
- "implementation_whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
+ "whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
}),
},
})
@@ -2032,3 +2034,44 @@
},
})
}
+
+func TestCcLibraryStaticHiddenVisibilityConvertedToFeature(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static changes hidden visibility flag to feature",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ cflags: ["-fvisibility=hidden"],
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `["visibility_hidden"]`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
+
+func TestCcLibraryStaticHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library_static changes hidden visibility flag to feature for specific os",
+ Blueprint: `
+cc_library_static {
+ name: "foo",
+ target: {
+ android: {
+ cflags: ["-fvisibility=hidden"],
+ },
+ },
+}`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+ "features": `select({
+ "//build/bazel/platforms/os:android": ["visibility_hidden"],
+ "//conditions:default": [],
+ })`,
+ "local_includes": `["."]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 20adddb..4df4d4d 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -76,17 +76,28 @@
static_libs: ["hostlib"],
},
},
+ static_libs: ["cc_test_lib1"],
+ shared_libs: ["cc_test_lib2"],
data: [":data_mod", "file.txt"],
data_bins: [":cc_bin"],
data_libs: [":cc_lib"],
cflags: ["-Wall"],
}
+
+cc_test_library {
+ name: "cc_test_lib1",
+ host_supported: true,
+ include_build_directory: false,
+}
` + simpleModuleDoNotConvertBp2build("cc_library", "foolib") +
simpleModuleDoNotConvertBp2build("cc_library_static", "hostlib") +
simpleModuleDoNotConvertBp2build("genrule", "data_mod") +
simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") +
- simpleModuleDoNotConvertBp2build("cc_test_library", "cc_lib"),
+ simpleModuleDoNotConvertBp2build("cc_library", "cc_lib") +
+ simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2"),
targets: []testBazelTarget{
+ {"cc_library_shared", "cc_test_lib1", AttrNameToString{}},
+ {"cc_library_static", "cc_test_lib1_bp2build_cc_library_static", AttrNameToString{}},
{"cc_test", "mytest", AttrNameToString{
"copts": `["-Wall"]`,
"data": `[
@@ -95,7 +106,7 @@
":cc_bin",
":cc_lib",
]`,
- "deps": `select({
+ "deps": `[":cc_test_lib1_bp2build_cc_library_static"] + select({
"//build/bazel/platforms/os:darwin": [":hostlib"],
"//build/bazel/platforms/os:linux_bionic": [":hostlib"],
"//build/bazel/platforms/os:linux_glibc": [":hostlib"],
@@ -106,7 +117,7 @@
"gtest": "True",
"isolated": "True",
"local_includes": `["."]`,
- "dynamic_deps": `select({
+ "dynamic_deps": `[":cc_test_lib2"] + select({
"//build/bazel/platforms/os:android": [":foolib"],
"//conditions:default": [],
})`,
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 8e17103..3d9f0a2 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -279,6 +279,10 @@
}
if len(selects) == 0 {
+ // If there is a default value, and there are no selects for this axis, print that without any selects.
+ if val, exists := selectMap[bazel.ConditionsDefaultSelectKey]; exists {
+ return prettyPrint(val, indent, emitZeroValues)
+ }
// No conditions (or all values are empty lists), so no need for a map.
return "", nil
}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 608fcd8..f598332 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -59,14 +59,17 @@
files = append(files, newFile("product_config", "arch_configuration.bzl", android.StarlarkArchConfigurations()))
- apiLevelsContent, err := json.Marshal(android.GetApiLevelsMap(cfg))
+ apiLevelsMap, err := android.GetApiLevelsMap(cfg)
+ if err != nil {
+ return nil, err
+ }
+ apiLevelsContent, err := json.Marshal(apiLevelsMap)
if err != nil {
return nil, err
}
files = append(files, newFile("api_levels", GeneratedBuildFileName, `exports_files(["api_levels.json"])`))
// TODO(b/269691302) value of apiLevelsContent is product variable dependent and should be avoided for soong injection
files = append(files, newFile("api_levels", "api_levels.json", string(apiLevelsContent)))
- files = append(files, newFile("api_levels", "api_levels.bzl", android.StarlarkApiLevelConfigs(cfg)))
files = append(files, newFile("api_levels", "platform_versions.bzl", platformVersionContents(cfg)))
files = append(files, newFile("allowlists", GeneratedBuildFileName, ""))
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 2f5dc3c..379f83b 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -159,10 +159,6 @@
},
{
dir: "api_levels",
- basename: "api_levels.bzl",
- },
- {
- dir: "api_levels",
basename: "platform_versions.bzl",
},
{
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index c821f59..e51f608 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -259,17 +259,20 @@
runJavaBinaryHostTestCase(t, Bp2buildTestCase{
Description: "java_binary_host with srcs, libs, resources.",
Filesystem: map[string]string{
- "test.mf": "Main-Class: com.android.test.MainClass",
- "res/a.res": "",
- "res/b.res": "",
- },
- Blueprint: `java_binary_host {
+ "adir/test.mf": "Main-Class: com.android.test.MainClass",
+ "adir/res/a.res": "",
+ "adir/res/b.res": "",
+ "adir/Android.bp": `java_binary_host {
name: "java-binary-host",
manifest: "test.mf",
srcs: ["a.java", "b.kt"],
java_resources: ["res/a.res", "res/b.res"],
+ bazel_module: { bp2build_available: true },
}
`,
+ },
+ Dir: "adir",
+ Blueprint: "",
ExpectedBazelTargets: []string{
MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
"srcs": `[
@@ -280,6 +283,7 @@
"res/a.res",
"res/b.res",
]`,
+ "resource_strip_prefix": `"adir"`,
"target_compatible_with": `select({
"//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
"//conditions:default": [],
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 24b763b..60766f4 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -283,21 +283,25 @@
func TestJavaLibraryResources(t *testing.T) {
runJavaLibraryTestCase(t, Bp2buildTestCase{
+ Dir: "adir",
Filesystem: map[string]string{
- "res/a.res": "",
- "res/b.res": "",
- "res/dir1/b.res": "",
- },
- Blueprint: `java_library {
+ "adir/res/a.res": "",
+ "adir/res/b.res": "",
+ "adir/res/dir1/b.res": "",
+ "adir/Android.bp": `java_library {
name: "java-lib-1",
- java_resources: ["res/a.res", "res/b.res"],
+ java_resources: ["res/a.res", "res/b.res"],
+ bazel_module: { bp2build_available: true },
}`,
+ },
+ Blueprint: "",
ExpectedBazelTargets: []string{
MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
"resources": `[
"res/a.res",
"res/b.res",
]`,
+ "resource_strip_prefix": `"adir"`,
}),
MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
},
diff --git a/bp2build/package_conversion_test.go b/bp2build/package_conversion_test.go
index 3704b2d..ce848e4 100644
--- a/bp2build/package_conversion_test.go
+++ b/bp2build/package_conversion_test.go
@@ -15,9 +15,10 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/genrule"
- "testing"
)
func registerDependentModules(ctx android.RegistrationContext) {
@@ -29,6 +30,7 @@
tests := []struct {
description string
modules string
+ fs map[string]string
expected []ExpectedRuleTarget
}{
{
@@ -50,8 +52,8 @@
"package",
"",
AttrNameToString{
- "default_applicable_licenses": `[":my_license"]`,
- "default_visibility": `["//visibility:public"]`,
+ "default_package_metadata": `[":my_license"]`,
+ "default_visibility": `["//visibility:public"]`,
},
android.HostAndDeviceDefault,
},
@@ -67,6 +69,57 @@
},
},
},
+ {
+ description: "package has METADATA file",
+ fs: map[string]string{
+ "METADATA": ``,
+ },
+ modules: `
+license {
+ name: "my_license",
+ visibility: [":__subpackages__"],
+ license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+ license_text: ["NOTICE"],
+}
+
+package {
+ default_applicable_licenses: ["my_license"],
+}
+`,
+ expected: []ExpectedRuleTarget{
+ {
+ "package",
+ "",
+ AttrNameToString{
+ "default_package_metadata": `[
+ ":my_license",
+ ":default_metadata_file",
+ ]`,
+ "default_visibility": `["//visibility:public"]`,
+ },
+ android.HostAndDeviceDefault,
+ },
+ {
+ "android_license",
+ "my_license",
+ AttrNameToString{
+ "license_kinds": `["SPDX-license-identifier-Apache-2.0"]`,
+ "license_text": `"NOTICE"`,
+ "visibility": `[":__subpackages__"]`,
+ },
+ android.HostAndDeviceDefault,
+ },
+ {
+ "filegroup",
+ "default_metadata_file",
+ AttrNameToString{
+ "applicable_licenses": `[]`,
+ "srcs": `["METADATA"]`,
+ },
+ android.HostAndDeviceDefault,
+ },
+ },
+ },
}
for _, test := range tests {
expected := make([]string, 0, len(test.expected))
@@ -80,6 +133,7 @@
ModuleTypeUnderTestFactory: android.PackageFactory,
Blueprint: test.modules,
ExpectedBazelTargets: expected,
+ Filesystem: test.fs,
})
}
}
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index ba42f34..ad07f68 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -1251,3 +1251,111 @@
srcs = ["main.cc"],
)`}})
}
+
+func TestSoongConfigModuleType_CombinedWithArchVariantProperties(t *testing.T) {
+ bp := `
+soong_config_bool_variable {
+ name: "my_bool_variable",
+}
+
+soong_config_string_variable {
+ name: "my_string_variable",
+ values: [
+ "value1",
+ "value2",
+ ],
+}
+
+soong_config_module_type {
+ name: "special_build_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "my_namespace",
+ bool_variables: ["my_bool_variable"],
+ variables: ["my_string_variable"],
+ properties: ["target.android.cflags", "cflags"],
+}
+
+special_build_cc_defaults {
+ name: "sample_cc_defaults",
+ target: {
+ android: {
+ cflags: ["-DFOO"],
+ },
+ },
+ soong_config_variables: {
+ my_bool_variable: {
+ target: {
+ android: {
+ cflags: ["-DBAR"],
+ },
+ },
+ conditions_default: {
+ target: {
+ android: {
+ cflags: ["-DBAZ"],
+ },
+ },
+ },
+ },
+ my_string_variable: {
+ value1: {
+ cflags: ["-DVALUE1_NOT_ANDROID"],
+ target: {
+ android: {
+ cflags: ["-DVALUE1"],
+ },
+ },
+ },
+ value2: {
+ target: {
+ android: {
+ cflags: ["-DVALUE2"],
+ },
+ },
+ },
+ conditions_default: {
+ target: {
+ android: {
+ cflags: ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
+ },
+ },
+ },
+ },
+ },
+}
+
+cc_binary {
+ name: "my_binary",
+ srcs: ["main.cc"],
+ defaults: ["sample_cc_defaults"],
+}`
+
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for library_linking_strategy",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{},
+ ExpectedBazelTargets: []string{`cc_binary(
+ name = "my_binary",
+ copts = select({
+ "//build/bazel/platforms/os:android": ["-DFOO"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:my_namespace__my_bool_variable__android": ["-DBAR"],
+ "//build/bazel/product_variables:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
+ "//build/bazel/product_variables:my_namespace__my_string_variable__value1__android": ["-DVALUE1"],
+ "//build/bazel/product_variables:my_namespace__my_string_variable__value2__android": ["-DVALUE2"],
+ "//conditions:default": [],
+ }),
+ local_includes = ["."],
+ srcs = ["main.cc"],
+ target_compatible_with = ["//build/bazel/platforms/os:android"],
+)`}})
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 6e919db..fd99ff0 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -317,6 +317,8 @@
One_to_many_prop *bool
Api *string // File describing the APIs of this module
+
+ Test_config_setting *bool // Used to test generation of config_setting targets
}
type customModule struct {
@@ -490,6 +492,27 @@
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+
+ if proptools.Bool(m.props.Test_config_setting) {
+ m.createConfigSetting(ctx)
+ }
+
+}
+
+func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) {
+ csa := bazel.ConfigSettingAttributes{
+ Flag_values: bazel.StringMapAttribute{
+ "//build/bazel/rules/my_string_setting": m.Name(),
+ },
+ }
+ ca := android.CommonAttributes{
+ Name: m.Name() + "_config_setting",
+ }
+ ctx.CreateBazelConfigSetting(
+ csa,
+ ca,
+ ctx.ModuleDir(),
+ )
}
var _ android.ApiProvider = (*customModule)(nil)
diff --git a/cc/Android.bp b/cc/Android.bp
index be2cc5a..f49dc1a 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -9,6 +9,7 @@
"blueprint",
"blueprint-pathtools",
"soong",
+ "soong-aidl-library",
"soong-android",
"soong-bazel",
"soong-cc-config",
@@ -22,7 +23,6 @@
srcs: [
"afdo.go",
"fdo_profile.go",
-
"androidmk.go",
"api_level.go",
"bp2build.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 980dd07..ce35b5c 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -124,17 +124,14 @@
}
}
}
- if c.Properties.IsSdkVariant {
+ if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
// Make the SDK variant uninstallable so that there are not two rules to install
// to the same location.
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-
- if c.Properties.SdkAndPlatformVariantVisibleToMake {
- // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
- // dependencies to the .sdk suffix when building a module that uses the SDK.
- entries.SetString("SOONG_SDK_VARIANT_MODULES",
- "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
- }
+ // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
+ // dependencies to the .sdk suffix when building a module that uses the SDK.
+ entries.SetString("SOONG_SDK_VARIANT_MODULES",
+ "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
}
},
},
diff --git a/cc/binary.go b/cc/binary.go
index 097f822..98b9923 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -661,7 +661,7 @@
// shared with cc_test
binaryAttrs := binaryBp2buildAttrs(ctx, m)
- tags := android.ApexAvailableTags(m)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
Rule_class: "cc_binary",
Bzl_load_location: "//build/bazel/rules/cc:cc_binary.bzl",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index c8f516c..fa98df4 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -17,6 +17,7 @@
"fmt"
"path/filepath"
"strings"
+ "sync"
"android/soong/android"
"android/soong/bazel"
@@ -37,6 +38,7 @@
protoSrcPartition = "proto"
aidlSrcPartition = "aidl"
syspropSrcPartition = "sysprop"
+ yaccSrcPartition = "yacc"
stubsSuffix = "_stub_libs_current"
)
@@ -67,6 +69,8 @@
Apex_available []string
+ Features bazel.StringListAttribute
+
sdkAttributes
tidyAttributes
@@ -151,6 +155,7 @@
// know the language of these sources until the genrule is executed.
cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
syspropSrcPartition: bazel.LabelPartition{Extensions: []string{".sysprop"}},
+ yaccSrcPartition: bazel.LabelPartition{Extensions: []string{".y", "yy"}},
}
return bazel.PartitionLabelListAttribute(ctx, &srcs, labels)
@@ -226,7 +231,7 @@
attrs := staticOrSharedAttributes{}
setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
- attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag))
+ attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutHiddenVisibility))
attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs))
@@ -268,7 +273,9 @@
attrs.Srcs_c = partitionedSrcs[cSrcPartition]
attrs.Srcs_as = partitionedSrcs[asSrcPartition]
- attrs.Apex_available = android.ConvertApexAvailableToTags(apexAvailable)
+ attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), apexAvailable)
+
+ attrs.Features.Append(convertHiddenVisibilityToFeatureStaticOrShared(ctx, module, isStatic))
if !partitionedSrcs[protoSrcPartition].IsEmpty() {
// TODO(b/208815215): determine whether this is used and add support if necessary
@@ -399,6 +406,12 @@
// Sysprop sources
syspropSrcs bazel.LabelListAttribute
+ // Yacc sources
+ yaccSrc *bazel.LabelAttribute
+ yaccFlags bazel.StringListAttribute
+ yaccGenLocationHeader bazel.BoolAttribute
+ yaccGenPositionHeader bazel.BoolAttribute
+
hdrs bazel.LabelListAttribute
rtti bazel.BoolAttribute
@@ -428,6 +441,12 @@
type filterOutFn func(string) bool
+// filterOutHiddenVisibility removes the flag specifying hidden visibility as
+// this flag is converted to a toolchain feature
+func filterOutHiddenVisibility(flag string) bool {
+ return flag == config.VisibilityHiddenFlag
+}
+
func filterOutStdFlag(flag string) bool {
return strings.HasPrefix(flag, "-std=")
}
@@ -481,7 +500,7 @@
instructionSet := proptools.StringDefault(props.Instruction_set, "")
if instructionSet == "arm" {
- ca.features.SetSelectValue(axis, config, []string{"arm_isa_arm", "-arm_isa_thumb"})
+ ca.features.SetSelectValue(axis, config, []string{"arm_isa_arm"})
} else if instructionSet != "" && instructionSet != "thumb" {
ctx.ModuleErrorf("Unknown value for instruction_set: %s", instructionSet)
}
@@ -490,7 +509,7 @@
// overridden. In Bazel we always allow overriding, via flags; however, this can cause
// incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other
// cases.
- ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutClangUnknownCflags))
+ ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutClangUnknownCflags, filterOutHiddenVisibility))
ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil))
ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, filterOutClangUnknownCflags))
ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, filterOutClangUnknownCflags))
@@ -517,7 +536,7 @@
productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{
"Cflags": &ca.copts,
"Asflags": &ca.asFlags,
- "CppFlags": &ca.cppFlags,
+ "Cppflags": &ca.cppFlags,
}
for propName, attr := range productVarPropNameToAttribute {
if productConfigProps, exists := productVariableProps[propName]; exists {
@@ -526,7 +545,7 @@
if !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
}
- newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name)
+ newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name())
attr.SetSelectValue(productConfigProp.ConfigurationAxis(), productConfigProp.SelectKey(), newFlags)
}
}
@@ -555,6 +574,12 @@
ca.asmSrcs = partitionedSrcs[asmSrcPartition]
ca.lSrcs = partitionedSrcs[lSrcPartition]
ca.llSrcs = partitionedSrcs[llSrcPartition]
+ if yacc := partitionedSrcs[yaccSrcPartition]; !yacc.IsEmpty() {
+ if len(yacc.Value.Includes) > 1 {
+ ctx.PropertyErrorf("srcs", "Found multiple yacc (.y/.yy) files in library")
+ }
+ ca.yaccSrc = bazel.MakeLabelAttribute(yacc.Value.Includes[0].Label)
+ }
ca.syspropSrcs = partitionedSrcs[syspropSrcPartition]
ca.absoluteIncludes.DeduplicateAxesFromBase()
@@ -717,6 +742,8 @@
compilerAttrs := compilerAttributes{}
linkerAttrs := linkerAttributes{}
+ var aidlLibs bazel.LabelList
+
// Iterate through these axes in a deterministic order. This is required
// because processing certain dependencies may result in concatenating
// elements along other axes. (For example, processing NoConfig may result
@@ -731,7 +758,13 @@
if baseCompilerProps.Lex != nil {
compilerAttrs.lexopts.SetSelectValue(axis, cfg, baseCompilerProps.Lex.Flags)
}
+ if baseCompilerProps.Yacc != nil {
+ compilerAttrs.yaccFlags.SetSelectValue(axis, cfg, baseCompilerProps.Yacc.Flags)
+ compilerAttrs.yaccGenLocationHeader.SetSelectValue(axis, cfg, baseCompilerProps.Yacc.Gen_location_hh)
+ compilerAttrs.yaccGenPositionHeader.SetSelectValue(axis, cfg, baseCompilerProps.Yacc.Gen_position_hh)
+ }
(&compilerAttrs).bp2buildForAxisAndConfig(ctx, axis, cfg, baseCompilerProps)
+ aidlLibs.Append(android.BazelLabelForModuleDeps(ctx, baseCompilerProps.Aidl.Libs))
}
var exportHdrs []string
@@ -762,8 +795,13 @@
if libraryProps, ok := archVariantLibraryProperties[axis][cfg].(*LibraryProperties); ok {
if axis == bazel.NoConfigAxis {
- compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
- compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, libraryProps.Stubs.Versions)
+ if libraryProps.Stubs.Symbol_file != nil {
+ compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
+ versions := android.CopyOf(libraryProps.Stubs.Versions)
+ normalizeVersions(ctx, versions)
+ versions = addCurrentVersionIfNotPresent(versions)
+ compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, versions)
+ }
}
if suffix := libraryProps.Suffix; suffix != nil {
compilerAttrs.suffix.SetSelectValue(axis, cfg, suffix)
@@ -799,7 +837,15 @@
(&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib)
(&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib)
- aidlDep := bp2buildCcAidlLibrary(ctx, module, compilerAttrs.aidlSrcs, linkerAttrs)
+ aidlDep := bp2buildCcAidlLibrary(
+ ctx, module,
+ compilerAttrs.aidlSrcs,
+ bazel.LabelListAttribute{
+ Value: aidlLibs,
+ },
+ linkerAttrs,
+ compilerAttrs,
+ )
if aidlDep != nil {
if lib, ok := module.linker.(*libraryDecorator); ok {
if proptools.Bool(lib.Properties.Aidl.Export_aidl_headers) {
@@ -810,6 +856,12 @@
}
}
+ // Create a cc_yacc_static_library if srcs contains .y/.yy files
+ // This internal target will produce an .a file that will be statically linked to the parent library
+ if yaccDep := bp2buildCcYaccLibrary(ctx, compilerAttrs, linkerAttrs); yaccDep != nil {
+ (&linkerAttrs).implementationWholeArchiveDeps.Add(yaccDep)
+ }
+
convertedLSrcs := bp2BuildLex(ctx, module.Name(), compilerAttrs)
(&compilerAttrs).srcs.Add(&convertedLSrcs.srcName)
(&compilerAttrs).cSrcs.Add(&convertedLSrcs.cSrcName)
@@ -833,6 +885,7 @@
features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module))
features = features.Append(bp2buildLtoFeatures(ctx, module))
+ features = features.Append(convertHiddenVisibilityToFeatureBase(ctx, module))
features.DeduplicateAxesFromBase()
addMuslSystemDynamicDeps(ctx, linkerAttrs)
@@ -847,6 +900,48 @@
}
}
+type ccYaccLibraryAttributes struct {
+ Src bazel.LabelAttribute
+ Flags bazel.StringListAttribute
+ Gen_location_hh bazel.BoolAttribute
+ Gen_position_hh bazel.BoolAttribute
+ Local_includes bazel.StringListAttribute
+ Implementation_deps bazel.LabelListAttribute
+ Implementation_dynamic_deps bazel.LabelListAttribute
+}
+
+func bp2buildCcYaccLibrary(ctx android.Bp2buildMutatorContext, ca compilerAttributes, la linkerAttributes) *bazel.LabelAttribute {
+ if ca.yaccSrc == nil {
+ return nil
+ }
+ yaccLibraryLabel := ctx.Module().Name() + "_yacc"
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_yacc_static_library",
+ Bzl_load_location: "//build/bazel/rules/cc:cc_yacc_library.bzl",
+ },
+ android.CommonAttributes{
+ Name: yaccLibraryLabel,
+ },
+ &ccYaccLibraryAttributes{
+ Src: *ca.yaccSrc,
+ Flags: ca.yaccFlags,
+ Gen_location_hh: ca.yaccGenLocationHeader,
+ Gen_position_hh: ca.yaccGenPositionHeader,
+ Local_includes: ca.localIncludes,
+ Implementation_deps: la.implementationDeps,
+ Implementation_dynamic_deps: la.implementationDynamicDeps,
+ },
+ )
+
+ yaccLibrary := &bazel.LabelAttribute{
+ Value: &bazel.Label{
+ Label: ":" + yaccLibraryLabel,
+ },
+ }
+ return yaccLibrary
+}
+
// As a workaround for b/261657184, we are manually adding the default value
// of system_dynamic_deps for the linux_musl os.
// TODO: Solve this properly
@@ -895,11 +990,16 @@
func bp2buildCcAidlLibrary(
ctx android.Bp2buildMutatorContext,
m *Module,
- aidlLabelList bazel.LabelListAttribute,
+ aidlSrcs bazel.LabelListAttribute,
+ aidlLibs bazel.LabelListAttribute,
linkerAttrs linkerAttributes,
+ compilerAttrs compilerAttributes,
) *bazel.LabelAttribute {
- if !aidlLabelList.IsEmpty() {
- aidlLibs, aidlSrcs := aidlLabelList.Partition(func(src bazel.Label) bool {
+ var aidlLibsFromSrcs, aidlFiles bazel.LabelListAttribute
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
+
+ if !aidlSrcs.IsEmpty() {
+ aidlLibsFromSrcs, aidlFiles = aidlSrcs.Partition(func(src bazel.Label) bool {
if fg, ok := android.ToFileGroupAsLibrary(ctx, src.OriginalModuleName); ok &&
fg.ShouldConvertToAidlLibrary(ctx) {
return true
@@ -907,57 +1007,71 @@
return false
})
- apexAvailableTags := android.ApexAvailableTags(ctx.Module())
- sdkAttrs := bp2BuildParseSdkAttributes(m)
-
- if !aidlSrcs.IsEmpty() {
+ if !aidlFiles.IsEmpty() {
aidlLibName := m.Name() + "_aidl_library"
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: "aidl_library",
Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
},
- android.CommonAttributes{Name: aidlLibName},
- &aidlLibraryAttributes{
- Srcs: aidlSrcs,
+ android.CommonAttributes{
+ Name: aidlLibName,
Tags: apexAvailableTags,
},
- )
- aidlLibs.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + aidlLibName}})
- }
-
- if !aidlLibs.IsEmpty() {
- ccAidlLibrarylabel := m.Name() + "_cc_aidl_library"
- // Since parent cc_library already has these dependencies, we can add them as implementation
- // deps so that they don't re-export
- implementationDeps := linkerAttrs.deps.Clone()
- implementationDeps.Append(linkerAttrs.implementationDeps)
- implementationDynamicDeps := linkerAttrs.dynamicDeps.Clone()
- implementationDynamicDeps.Append(linkerAttrs.implementationDynamicDeps)
-
- ctx.CreateBazelTargetModule(
- bazel.BazelTargetModuleProperties{
- Rule_class: "cc_aidl_library",
- Bzl_load_location: "//build/bazel/rules/cc:cc_aidl_library.bzl",
- },
- android.CommonAttributes{Name: ccAidlLibrarylabel},
- &ccAidlLibraryAttributes{
- Deps: aidlLibs,
- Implementation_deps: *implementationDeps,
- Implementation_dynamic_deps: *implementationDynamicDeps,
- Tags: apexAvailableTags,
- sdkAttributes: sdkAttrs,
+ &aidlLibraryAttributes{
+ Srcs: aidlFiles,
},
)
- label := &bazel.LabelAttribute{
- Value: &bazel.Label{
- Label: ":" + ccAidlLibrarylabel,
- },
- }
- return label
+ aidlLibsFromSrcs.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + aidlLibName}})
}
}
+ allAidlLibs := aidlLibs.Clone()
+ allAidlLibs.Append(aidlLibsFromSrcs)
+
+ if !allAidlLibs.IsEmpty() {
+ ccAidlLibrarylabel := m.Name() + "_cc_aidl_library"
+ // Since parent cc_library already has these dependencies, we can add them as implementation
+ // deps so that they don't re-export
+ implementationDeps := linkerAttrs.deps.Clone()
+ implementationDeps.Append(linkerAttrs.implementationDeps)
+ implementationDynamicDeps := linkerAttrs.dynamicDeps.Clone()
+ implementationDynamicDeps.Append(linkerAttrs.implementationDynamicDeps)
+
+ sdkAttrs := bp2BuildParseSdkAttributes(m)
+
+ exportedIncludes := bp2BuildParseExportedIncludes(ctx, m, &compilerAttrs.includes)
+ includeAttrs := includesAttributes{
+ Export_includes: exportedIncludes.Includes,
+ Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Local_includes: compilerAttrs.localIncludes,
+ Absolute_includes: compilerAttrs.absoluteIncludes,
+ }
+
+ ctx.CreateBazelTargetModule(
+ bazel.BazelTargetModuleProperties{
+ Rule_class: "cc_aidl_library",
+ Bzl_load_location: "//build/bazel/rules/cc:cc_aidl_library.bzl",
+ },
+ android.CommonAttributes{Name: ccAidlLibrarylabel},
+ &ccAidlLibraryAttributes{
+ Deps: *allAidlLibs,
+ Implementation_deps: *implementationDeps,
+ Implementation_dynamic_deps: *implementationDynamicDeps,
+ Tags: apexAvailableTags,
+ sdkAttributes: sdkAttrs,
+ includesAttributes: includeAttrs,
+ },
+ )
+ label := &bazel.LabelAttribute{
+ Value: &bazel.Label{
+ Label: ":" + ccAidlLibrarylabel,
+ },
+ }
+ return label
+ }
+
return nil
}
@@ -1036,11 +1150,7 @@
_, staticLibs = android.RemoveFromList(versionLib, staticLibs)
// only add the dep if it is not in progress
if !versionLibAlreadyInDeps {
- if isBinary {
- wholeStaticLibs = append(wholeStaticLibs, versionLib)
- } else {
- la.implementationWholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, []string{versionLib}, props.Exclude_static_libs))
- }
+ wholeStaticLibs = append(wholeStaticLibs, versionLib)
}
}
}
@@ -1107,8 +1217,11 @@
// having stubs or not, so Bazel select() statement can be used to choose
// source/stub variants of them.
apexAvailable := module.ApexAvailable()
- setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0)
- setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1)
+ setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false)
+ setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false)
+ if len(systemSharedLibs) > 0 {
+ setStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true)
+ }
}
if !BoolDefault(props.Pack_relocations, packRelocationsDefault) {
@@ -1153,6 +1266,9 @@
}
la.additionalLinkerInputs.SetSelectValue(axis, config, additionalLinkerInputs)
+ if axis == bazel.OsConfigurationAxis && (config == bazel.OsDarwin || config == bazel.OsLinux || config == bazel.OsWindows) {
+ linkerFlags = append(linkerFlags, props.Host_ldlibs...)
+ }
la.linkopts.SetSelectValue(axis, config, linkerFlags)
if axisFeatures != nil {
@@ -1177,45 +1293,185 @@
return !differ
}
-func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
- config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) {
+var (
+ apiDomainConfigSettingKey = android.NewOnceKey("apiDomainConfigSettingKey")
+ apiDomainConfigSettingLock sync.Mutex
+)
- depsWithStubs := []bazel.Label{}
- for _, l := range dynamicLibs.Includes {
- dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
- if d, ok := dep.(*Module); ok && d.HasStubsVariants() {
- depApexAvailable := d.ApexAvailable()
- if !availableToSameApexes(apexAvailable, depApexAvailable) {
- depsWithStubs = append(depsWithStubs, l)
- }
+func getApiDomainConfigSettingMap(config android.Config) *map[string]bool {
+ return config.Once(apiDomainConfigSettingKey, func() interface{} {
+ return &map[string]bool{}
+ }).(*map[string]bool)
+}
+
+var (
+ testApexNameToApiDomain = map[string]string{
+ "test_broken_com.android.art": "com.android.art",
+ }
+)
+
+// GetApiDomain returns the canonical name of the apex. This is synonymous to the apex_name definition.
+// https://cs.android.com/android/_/android/platform/build/soong/+/e3f0281b8897da1fe23b2f4f3a05f1dc87bcc902:apex/prebuilt.go;l=81-83;drc=2dc7244af985a6ad701b22f1271e606cabba527f;bpv=1;bpt=0
+// For test apexes, it uses a naming convention heuristic to determine the api domain.
+// TODO (b/281548611): Move this build/soong/android
+func GetApiDomain(apexName string) string {
+ if apiDomain, exists := testApexNameToApiDomain[apexName]; exists {
+ return apiDomain
+ }
+ // Remove `test_` prefix
+ return strings.TrimPrefix(apexName, "test_")
+}
+
+// Create a config setting for this apex in build/bazel/rules/apex
+// The use case for this is stub/impl selection in cc libraries
+// Long term, these config_setting(s) should be colocated with the respective apex definitions.
+// Note that this is an anti-pattern: The config_setting should be created from the apex definition
+// and not from a cc_library.
+// This anti-pattern is needed today since not all apexes have been allowlisted.
+func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName string) {
+ if apexName == android.AvailableToPlatform || apexName == android.AvailableToAnyApex {
+ // These correspond to android-non_apex and android-in_apex
+ return
+ }
+ apiDomainConfigSettingLock.Lock()
+ defer apiDomainConfigSettingLock.Unlock()
+
+ // Return if a config_setting has already been created
+ apiDomain := GetApiDomain(apexName)
+ acsm := getApiDomainConfigSettingMap(ctx.Config())
+ if _, exists := (*acsm)[apiDomain]; exists {
+ return
+ }
+ (*acsm)[apiDomain] = true
+
+ csa := bazel.ConfigSettingAttributes{
+ Flag_values: bazel.StringMapAttribute{
+ "//build/bazel/rules/apex:api_domain": apiDomain,
+ },
+ // Constraint this to android
+ Constraint_values: bazel.MakeLabelListAttribute(
+ bazel.MakeLabelList(
+ []bazel.Label{
+ bazel.Label{Label: "//build/bazel/platforms/os:android"},
+ },
+ ),
+ ),
+ }
+ ca := android.CommonAttributes{
+ Name: apiDomain,
+ }
+ ctx.CreateBazelConfigSetting(
+ csa,
+ ca,
+ "build/bazel/rules/apex",
+ )
+}
+
+func inApexConfigSetting(apexAvailable string) string {
+ if apexAvailable == android.AvailableToPlatform {
+ return bazel.AndroidPlatform
+ }
+ if apexAvailable == android.AvailableToAnyApex {
+ return bazel.AndroidAndInApex
+ }
+ apiDomain := GetApiDomain(apexAvailable)
+ return "//build/bazel/rules/apex:" + apiDomain
+}
+
+// Inputs to stub vs impl selection.
+type stubSelectionInfo struct {
+ // Label of the implementation library (e.g. //bionic/libc:libc)
+ impl bazel.Label
+ // Axis containing the implementation library
+ axis bazel.ConfigurationAxis
+ // Axis key containing the implementation library
+ config string
+ // API domain of the apex
+ // For test apexes (test_com.android.foo), this will be the source apex (com.android.foo)
+ apiDomain string
+ // List of dep labels
+ dynamicDeps *bazel.LabelListAttribute
+ // Boolean value for determining if the dep is in the same api domain
+ // If false, the label will be rewritten to to the stub label
+ sameApiDomain bool
+}
+
+func useStubOrImplInApexWithName(ssi stubSelectionInfo) {
+ lib := ssi.impl
+ if !ssi.sameApiDomain {
+ lib = bazel.Label{
+ Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(lib.OriginalModuleName, ":"),
}
}
- if len(depsWithStubs) > 0 {
- implDynamicDeps := bazel.SubtractBazelLabelList(dynamicLibs, bazel.MakeLabelList(depsWithStubs))
- dynamicDeps.SetSelectValue(axis, config, implDynamicDeps)
+ // Create a select statement specific to this apex
+ inApexSelectValue := ssi.dynamicDeps.SelectValue(bazel.OsAndInApexAxis, inApexConfigSetting(ssi.apiDomain))
+ (&inApexSelectValue).Append(bazel.MakeLabelList([]bazel.Label{lib}))
+ ssi.dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, inApexConfigSetting(ssi.apiDomain), bazel.FirstUniqueBazelLabelList(inApexSelectValue))
+ // Delete the library from the common config for this apex
+ implDynamicDeps := ssi.dynamicDeps.SelectValue(ssi.axis, ssi.config)
+ implDynamicDeps = bazel.SubtractBazelLabelList(implDynamicDeps, bazel.MakeLabelList([]bazel.Label{ssi.impl}))
+ ssi.dynamicDeps.SetSelectValue(ssi.axis, ssi.config, implDynamicDeps)
+ if ssi.axis == bazel.NoConfigAxis {
+ // Set defaults. Defaults (i.e. host) should use impl and not stubs.
+ defaultSelectValue := ssi.dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
+ (&defaultSelectValue).Append(bazel.MakeLabelList([]bazel.Label{ssi.impl}))
+ ssi.dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
+ }
+}
- stubLibLabels := []bazel.Label{}
- for _, l := range depsWithStubs {
- stubLabelInApiSurfaces := bazel.Label{
- Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(l.OriginalModuleName, ":"),
- }
- stubLibLabels = append(stubLibLabels, stubLabelInApiSurfaces)
+func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
+ config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
+
+ // Create a config_setting for each apex_available.
+ // This will be used to select impl of a dep if dep is available to the same apex.
+ for _, aa := range apexAvailable {
+ createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
+ }
+
+ apiDomainForSelects := []string{}
+ for _, apex := range apexAvailable {
+ apiDomainForSelects = append(apiDomainForSelects, GetApiDomain(apex))
+ }
+ // Always emit a select statement for the platform variant.
+ // This ensures that b build //foo --config=android works
+ // Soong always creates a platform variant even when the library might not be available to platform.
+ if !android.InList(android.AvailableToPlatform, apiDomainForSelects) {
+ apiDomainForSelects = append(apiDomainForSelects, android.AvailableToPlatform)
+ }
+ apiDomainForSelects = android.SortedUniqueStrings(apiDomainForSelects)
+
+ // Create a select for each apex this library could be included in.
+ for _, l := range dynamicLibs.Includes {
+ dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
+ if c, ok := dep.(*Module); !ok || !c.HasStubsVariants() {
+ continue
}
- inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
- nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
- defaultSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
- if axis == bazel.NoConfigAxis {
- (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
- (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
- (&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
- dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
- dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
- dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
- } else if config == bazel.OsAndroid {
- (&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
- (&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
- dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
- dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
+ // TODO (b/280339069): Decrease the verbosity of the generated BUILD files
+ for _, apiDomain := range apiDomainForSelects {
+ var sameApiDomain bool
+ if apiDomain == android.AvailableToPlatform {
+ // Platform variants in Soong use equality of apex_available for stub/impl selection.
+ // https://cs.android.com/android/_/android/platform/build/soong/+/316b0158fe57ee7764235923e7c6f3d530da39c6:cc/cc.go;l=3393-3404;drc=176271a426496fa2688efe2b40d5c74340c63375;bpv=1;bpt=0
+ // One of the factors behind this design choice is cc_test
+ // Tests only have a platform variant, and using equality of apex_available ensures
+ // that tests of an apex library gets its implementation and not stubs.
+ // TODO (b/280343104): Discuss if we can drop this special handling for platform variants.
+ sameApiDomain = availableToSameApexes(apexAvailable, dep.(*Module).ApexAvailable())
+ if linkable, ok := ctx.Module().(LinkableInterface); ok && linkable.Bootstrap() {
+ sameApiDomain = true
+ }
+ } else {
+ sameApiDomain = android.InList(apiDomain, dep.(*Module).ApexAvailable())
+ }
+ ssi := stubSelectionInfo{
+ impl: l,
+ axis: axis,
+ config: config,
+ apiDomain: apiDomain,
+ dynamicDeps: dynamicDeps,
+ sameApiDomain: sameApiDomain,
+ }
+ useStubOrImplInApexWithName(ssi)
}
}
}
@@ -1266,7 +1522,7 @@
// Collect all the configurations that an include or exclude property exists for.
// We want to iterate all configurations rather than either the include or exclude because, for a
// particular configuration, we may have either only an include or an exclude to handle.
- productConfigProps := make(map[android.ProductConfigProperty]bool, len(props)+len(excludeProps))
+ productConfigProps := make(map[android.ProductConfigOrSoongConfigProperty]bool, len(props)+len(excludeProps))
for p := range props {
productConfigProps[p] = true
}
@@ -1312,7 +1568,6 @@
la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, toRemove)
- la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, toRemove)
stubsToRemove := make([]bazel.Label, 0, len(la.usedSystemDynamicDepAsDynamicDep))
for _, lib := range toRemove.Includes {
stubLabelInApiSurfaces := bazel.Label{
@@ -1320,7 +1575,12 @@
}
stubsToRemove = append(stubsToRemove, stubLabelInApiSurfaces)
}
- la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.MakeLabelList(stubsToRemove))
+ // system libraries (e.g. libc, libm, libdl) belong the com.android.runtime api domain
+ // dedupe the stubs of these libraries from the other api domains (platform, other_apexes...)
+ for _, aa := range ctx.Module().(*Module).ApexAvailable() {
+ la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, inApexConfigSetting(aa), bazel.MakeLabelList(stubsToRemove))
+ }
+ la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList(stubsToRemove))
}
la.deps.ResolveExcludes()
@@ -1547,3 +1807,38 @@
}
return ltoStringFeatures
}
+
+func convertHiddenVisibilityToFeatureBase(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
+ visibilityHiddenFeature := bazel.StringListAttribute{}
+ bp2BuildPropParseHelper(ctx, m, &BaseCompilerProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+ if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+ convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, baseCompilerProps.Cflags)
+ }
+ })
+ return visibilityHiddenFeature
+}
+
+func convertHiddenVisibilityToFeatureStaticOrShared(ctx android.BazelConversionPathContext, m *Module, isStatic bool) bazel.StringListAttribute {
+ visibilityHiddenFeature := bazel.StringListAttribute{}
+ if isStatic {
+ bp2BuildPropParseHelper(ctx, m, &StaticProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+ if staticProps, ok := props.(*StaticProperties); ok {
+ convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, staticProps.Static.Cflags)
+ }
+ })
+ } else {
+ bp2BuildPropParseHelper(ctx, m, &SharedProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
+ if sharedProps, ok := props.(*SharedProperties); ok {
+ convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, sharedProps.Shared.Cflags)
+ }
+ })
+ }
+
+ return visibilityHiddenFeature
+}
+
+func convertHiddenVisibilityToFeatureHelper(feature *bazel.StringListAttribute, axis bazel.ConfigurationAxis, configString string, cflags []string) {
+ if inList(config.VisibilityHiddenFlag, cflags) {
+ feature.SetSelectValue(axis, configString, []string{"visibility_hidden"})
+ }
+}
diff --git a/cc/builder.go b/cc/builder.go
index fef00d4..f5e0dcc 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -125,6 +125,14 @@
},
"objcopyCmd", "prefix")
+ // Rule to run objcopy --remove-section=.llvm_addrsig on a partially linked object
+ noAddrSig = pctx.AndroidStaticRule("noAddrSig",
+ blueprint.RuleParams{
+ Command: "rm -f ${out} && $objcopyCmd --remove-section=.llvm_addrsig ${in} ${out}",
+ CommandDeps: []string{"$objcopyCmd"},
+ },
+ "objcopyCmd")
+
_ = pctx.SourcePathVariable("stripPath", "build/soong/scripts/strip.sh")
_ = pctx.SourcePathVariable("xzCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/xz")
_ = pctx.SourcePathVariable("createMiniDebugInfo", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/create_minidebuginfo")
@@ -1008,6 +1016,21 @@
})
}
+// Generate a rule for running objcopy --remove-section=.llvm_addrsig on a partially linked object
+func transformObjectNoAddrSig(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath) {
+ objcopyCmd := "${config.ClangBin}/llvm-objcopy"
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: noAddrSig,
+ Description: "remove addrsig " + outputFile.Base(),
+ Output: outputFile,
+ Input: inputFile,
+ Args: map[string]string{
+ "objcopyCmd": objcopyCmd,
+ },
+ })
+}
+
// Registers a build statement to invoke `strip` (to discard symbols and data from object files).
func transformStrip(ctx android.ModuleContext, inputFile android.Path,
outputFile android.WritablePath, flags StripFlags) {
diff --git a/cc/cc.go b/cc/cc.go
index 1997e94..f4b5655 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -27,6 +27,7 @@
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
+ "android/soong/aidl_library"
"android/soong/android"
"android/soong/bazel/cquery"
"android/soong/cc/config"
@@ -110,6 +111,9 @@
// Used by DepsMutator to pass system_shared_libs information to check_elf_file.py.
SystemSharedLibs []string
+ // Used by DepMutator to pass aidl_library modules to aidl compiler
+ AidlLibs []string
+
// If true, statically link the unwinder into native libraries/binaries.
StaticUnwinderIfLegacy bool
@@ -182,6 +186,9 @@
// For Darwin builds, the path to the second architecture's output that should
// be combined with this architectures's output into a FAT MachO file.
DarwinSecondArchOutput android.OptionalPath
+
+ // Paths to direct srcs and transitive include dirs from direct aidl_library deps
+ AidlLibraryInfos []aidl_library.AidlLibraryInfo
}
// LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module
@@ -765,6 +772,7 @@
stubImplDepTag = dependencyTag{name: "stub_impl"}
JniFuzzLibTag = dependencyTag{name: "jni_fuzz_lib_tag"}
FdoProfileTag = dependencyTag{name: "fdo_profile"}
+ aidlLibraryTag = dependencyTag{name: "aidl_library"}
)
func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
@@ -1086,7 +1094,7 @@
panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", c.BaseModuleName()))
}
-func (c *Module) FuzzSharedLibraries() android.Paths {
+func (c *Module) FuzzSharedLibraries() android.RuleBuilderInstalls {
if fuzzer, ok := c.compiler.(*fuzzBinary); ok {
return fuzzer.sharedLibraries
}
@@ -1890,37 +1898,49 @@
c.bazelHandler.QueueBazelCall(ctx, c.getBazelModuleLabel(ctx))
}
-var (
- mixedBuildSupportedCcTest = []string{
- "adbd_test",
- "adb_crypto_test",
- "adb_pairing_auth_test",
- "adb_pairing_connection_test",
- "adb_tls_connection_test",
- }
-)
-
// IsMixedBuildSupported returns true if the module should be analyzed by Bazel
-// in any of the --bazel-mode(s). This filters at the module level and takes
-// precedence over the allowlists in allowlists/allowlists.go.
+// in any of the --bazel-mode(s).
func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
- _, isForTesting := ctx.Config().BazelContext.(android.MockBazelContext)
- if c.testBinary() && !android.InList(c.Name(), mixedBuildSupportedCcTest) && !isForTesting {
- // Per-module rollout of mixed-builds for cc_test modules.
+ if !allEnabledSanitizersSupportedByBazel(c) {
+ //TODO(b/278772861) support sanitizers in Bazel rules
return false
}
-
- // TODO(b/261058727): Remove this (enable mixed builds for modules with UBSan)
- // Currently we can only support ubsan when minimum runtime is used.
- return c.bazelHandler != nil && (!isUbsanEnabled(c) || c.MinimalRuntimeNeeded())
+ return c.bazelHandler != nil
}
-func isUbsanEnabled(c *Module) bool {
+func allEnabledSanitizersSupportedByBazel(c *Module) bool {
if c.sanitize == nil {
- return false
+ return true
}
sanitizeProps := &c.sanitize.Properties.SanitizeMutated
- return Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
+
+ unsupportedSanitizers := []*bool{
+ sanitizeProps.Safestack,
+ sanitizeProps.Cfi,
+ sanitizeProps.Scudo,
+ BoolPtr(len(c.sanitize.Properties.Sanitize.Recover) > 0),
+ BoolPtr(c.sanitize.Properties.Sanitize.Blocklist != nil),
+ }
+ for _, san := range unsupportedSanitizers {
+ if Bool(san) {
+ return false
+ }
+ }
+
+ for _, san := range Sanitizers {
+ if san == intOverflow {
+ // TODO(b/261058727): enable mixed builds for all modules with UBSan
+ // Currently we can only support ubsan when minimum runtime is used.
+ ubsanEnabled := Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
+ if ubsanEnabled && !c.MinimalRuntimeNeeded() {
+ return false
+ }
+ } else if c.sanitize.isSanitizerEnabled(san) {
+ return false
+ }
+ }
+
+ return true
}
func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey {
@@ -1964,6 +1984,67 @@
c.maybeInstall(mctx, apexInfo)
}
+func moduleContextFromAndroidModuleContext(actx android.ModuleContext, c *Module) ModuleContext {
+ ctx := &moduleContext{
+ ModuleContext: actx,
+ moduleContextImpl: moduleContextImpl{
+ mod: c,
+ },
+ }
+ ctx.ctx = ctx
+ return ctx
+}
+
+// TODO (b/277651159): Remove this allowlist
+var (
+ skipStubLibraryMultipleApexViolation = map[string]bool{
+ "libclang_rt.asan": true,
+ "libclang_rt.hwasan": true,
+ // runtime apex
+ "libc": true,
+ "libc_hwasan": true,
+ "libdl_android": true,
+ "libm": true,
+ "libdl": true,
+ // art apex
+ "libandroidio": true,
+ "libdexfile": true,
+ "libnativebridge": true,
+ "libnativehelper": true,
+ "libnativeloader": true,
+ "libsigchain": true,
+ }
+)
+
+// Returns true if a stub library could be installed in multiple apexes
+func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) bool {
+ // If this is not an apex variant, no check necessary
+ if !c.InAnyApex() {
+ return false
+ }
+ // If this is not a stub library, no check necessary
+ if !c.HasStubsVariants() {
+ return false
+ }
+ // Skip the allowlist
+ // Use BaseModuleName so that this matches prebuilts.
+ if _, exists := skipStubLibraryMultipleApexViolation[c.BaseModuleName()]; exists {
+ return false
+ }
+
+ _, aaWithoutTestApexes, _ := android.ListSetDifference(c.ApexAvailable(), c.TestApexes())
+ // Stub libraries should not have more than one apex_available
+ if len(aaWithoutTestApexes) > 1 {
+ return true
+ }
+ // Stub libraries should not use the wildcard
+ if aaWithoutTestApexes[0] == android.AvailableToAnyApex {
+ return true
+ }
+ // Default: no violation
+ return false
+}
+
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
// Handle the case of a test module split by `test_per_src` mutator.
//
@@ -1983,19 +2064,17 @@
c.makeLinkType = GetMakeLinkType(actx, c)
- ctx := &moduleContext{
- ModuleContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: c,
- },
- }
- ctx.ctx = ctx
+ ctx := moduleContextFromAndroidModuleContext(actx, c)
deps := c.depsToPaths(ctx)
if ctx.Failed() {
return
}
+ if c.stubLibraryMultipleApexViolation(actx) {
+ actx.PropertyErrorf("apex_available",
+ "Stub libraries should have a single apex_available (test apexes excluded). Got %v", c.ApexAvailable())
+ }
if c.Properties.Clang != nil && *c.Properties.Clang == false {
ctx.PropertyErrorf("clang", "false (GCC) is no longer supported")
} else if c.Properties.Clang != nil && !ctx.DeviceConfig().BuildBrokenClangProperty() {
@@ -2680,6 +2759,14 @@
}
}
+ if len(deps.AidlLibs) > 0 {
+ actx.AddDependency(
+ c,
+ aidlLibraryTag,
+ deps.AidlLibs...,
+ )
+ }
+
updateImportedLibraryDependency(ctx)
}
@@ -2984,6 +3071,17 @@
return
}
+ if depTag == aidlLibraryTag {
+ if ctx.OtherModuleHasProvider(dep, aidl_library.AidlLibraryProvider) {
+ depPaths.AidlLibraryInfos = append(
+ depPaths.AidlLibraryInfos,
+ ctx.OtherModuleProvider(
+ dep,
+ aidl_library.AidlLibraryProvider).(aidl_library.AidlLibraryInfo),
+ )
+ }
+ }
+
ccDep, ok := dep.(LinkableInterface)
if !ok {
@@ -3918,8 +4016,8 @@
// TODO(b/244431896) properly convert cc_test_library to its own macro. This
// will let them add implicit compile deps on gtest, for example.
//
- // For now, treat them as regular shared libraries.
- return sharedLibrary
+ // For now, treat them as regular libraries.
+ return fullLibrary
} else if c.CcLibrary() {
static := false
shared := false
diff --git a/cc/cc_test.go b/cc/cc_test.go
index b986511..422df73 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -24,6 +24,7 @@
"strings"
"testing"
+ "android/soong/aidl_library"
"android/soong/android"
"android/soong/bazel/cquery"
)
@@ -38,6 +39,7 @@
var prepareForCcTest = android.GroupFixturePreparers(
PrepareForTestWithCcIncludeVndk,
+ aidl_library.PrepareForTestWithAidlLibrary,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.DeviceVndkVersion = StringPtr("current")
variables.ProductVndkVersion = StringPtr("current")
@@ -59,7 +61,7 @@
func mixedBuildsPrepareMutator(ctx android.BottomUpMutatorContext) {
if m := ctx.Module(); m.Enabled() {
if mixedBuildMod, ok := m.(android.MixedBuildBuildable); ok {
- if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) {
+ if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) == android.MixedBuildEnabled {
mixedBuildMod.QueueBazelCall(ctx)
}
}
@@ -3114,6 +3116,11 @@
whole_static_libs: ["whole_static_dep"],
shared_libs: ["shared_dep"],
gtest: false,
+ sanitize: {
+ // cc_test modules default to memtag_heap: true,
+ // but this adds extra dependencies that we don't care about
+ never: true,
+ }
}
cc_binary {
name: "binary",
@@ -3573,9 +3580,6 @@
}
func TestStubsForLibraryInMultipleApexes(t *testing.T) {
- // TODO(b/275313114): Test exposes non-determinism which should be corrected and the test
- // reenabled.
- t.Skip()
t.Parallel()
ctx := testCc(t, `
cc_library_shared {
@@ -3680,6 +3684,130 @@
}
}
+func TestMixedBuildUsesStubs(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libFoo",
+ bazel_module: { label: "//:libFoo" },
+ srcs: ["foo.c"],
+ stubs: {
+ symbol_file: "foo.map.txt",
+ versions: ["current"],
+ },
+ apex_available: ["bar", "a1"],
+ }
+
+ cc_library_shared {
+ name: "libBar",
+ srcs: ["bar.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["a1"],
+ }
+
+ cc_library_shared {
+ name: "libA1",
+ srcs: ["a1.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["a1"],
+ }
+
+ cc_library_shared {
+ name: "libBarA1",
+ srcs: ["bara1.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["bar", "a1"],
+ }
+
+ cc_library_shared {
+ name: "libAnyApex",
+ srcs: ["anyApex.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["//apex_available:anyapex"],
+ }
+
+ cc_library_shared {
+ name: "libBaz",
+ srcs: ["baz.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["baz"],
+ }
+
+ cc_library_shared {
+ name: "libQux",
+ srcs: ["qux.c"],
+ shared_libs: ["libFoo"],
+ apex_available: ["qux", "bar"],
+ }`
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "out/bazel",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//:libFoo": {
+ RootDynamicLibraries: []string{"libFoo.so"},
+ },
+ "//:libFoo_stub_libs-current": {
+ RootDynamicLibraries: []string{"libFoo_stub_libs-current.so"},
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp)
+ ctx := result.TestContext
+
+ variants := ctx.ModuleVariantsForTests("libFoo")
+ expectedVariants := []string{
+ "android_arm64_armv8-a_shared",
+ "android_arm64_armv8-a_shared_current",
+ "android_arm_armv7-a-neon_shared",
+ "android_arm_armv7-a-neon_shared_current",
+ }
+ variantsMismatch := false
+ if len(variants) != len(expectedVariants) {
+ variantsMismatch = true
+ } else {
+ for _, v := range expectedVariants {
+ if !inList(v, variants) {
+ variantsMismatch = false
+ }
+ }
+ }
+ if variantsMismatch {
+ t.Errorf("variants of libFoo expected:\n")
+ for _, v := range expectedVariants {
+ t.Errorf("%q\n", v)
+ }
+ t.Errorf(", but got:\n")
+ for _, v := range variants {
+ t.Errorf("%q\n", v)
+ }
+ }
+
+ linkAgainstFoo := []string{"libBarA1"}
+ linkAgainstFooStubs := []string{"libBar", "libA1", "libBaz", "libQux", "libAnyApex"}
+
+ libFooPath := "out/bazel/execroot/__main__/libFoo.so"
+ for _, lib := range linkAgainstFoo {
+ libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
+ libFlags := libLinkRule.Args["libFlags"]
+ if !strings.Contains(libFlags, libFooPath) {
+ t.Errorf("%q: %q is not found in %q", lib, libFooPath, libFlags)
+ }
+ }
+
+ libFooStubPath := "out/bazel/execroot/__main__/libFoo_stub_libs-current.so"
+ for _, lib := range linkAgainstFooStubs {
+ libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
+ libFlags := libLinkRule.Args["libFlags"]
+ if !strings.Contains(libFlags, libFooStubPath) {
+ t.Errorf("%q: %q is not found in %q", lib, libFooStubPath, libFlags)
+ }
+ }
+}
+
func TestVersioningMacro(t *testing.T) {
t.Parallel()
for _, tc := range []struct{ moduleName, expected string }{
@@ -4292,9 +4420,65 @@
}
}
+func TestAidlLibraryWithHeader(t *testing.T) {
+ t.Parallel()
+ ctx := android.GroupFixturePreparers(
+ prepareForCcTest,
+ aidl_library.PrepareForTestWithAidlLibrary,
+ android.MockFS{
+ "package_bar/Android.bp": []byte(`
+ aidl_library {
+ name: "bar",
+ srcs: ["x/y/Bar.aidl"],
+ strip_import_prefix: "x",
+ }
+ `)}.AddToFixture(),
+ android.MockFS{
+ "package_foo/Android.bp": []byte(`
+ aidl_library {
+ name: "foo",
+ srcs: ["a/b/Foo.aidl"],
+ strip_import_prefix: "a",
+ deps: ["bar"],
+ }
+ cc_library {
+ name: "libfoo",
+ aidl: {
+ libs: ["foo"],
+ }
+ }
+ `),
+ }.AddToFixture(),
+ ).RunTest(t).TestContext
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
+ manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl.sbox.textproto"))
+ aidlCommand := manifest.Commands[0].GetCommand()
+
+ expectedAidlFlags := "-Ipackage_foo/a -Ipackage_bar/x"
+ if !strings.Contains(aidlCommand, expectedAidlFlags) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlags)
+ }
+
+ outputs := strings.Join(libfoo.AllOutputs(), " ")
+
+ android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl/b/BpFoo.h")
+ android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl/b/BnFoo.h")
+ android.AssertStringDoesContain(t, "aidl-generated header", outputs, "gen/aidl/b/Foo.h")
+ android.AssertStringDoesContain(t, "aidl-generated cpp", outputs, "b/Foo.cpp")
+ // Confirm that the aidl header doesn't get compiled to cpp and h files
+ android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl/y/BpBar.h")
+ android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl/y/BnBar.h")
+ android.AssertStringDoesNotContain(t, "aidl-generated header", outputs, "gen/aidl/y/Bar.h")
+ android.AssertStringDoesNotContain(t, "aidl-generated cpp", outputs, "y/Bar.cpp")
+}
+
func TestAidlFlagsPassedToTheAidlCompiler(t *testing.T) {
t.Parallel()
- ctx := testCc(t, `
+ ctx := android.GroupFixturePreparers(
+ prepareForCcTest,
+ aidl_library.PrepareForTestWithAidlLibrary,
+ ).RunTestWithBp(t, `
cc_library {
name: "libfoo",
srcs: ["a/Foo.aidl"],
@@ -4579,7 +4763,15 @@
})
t.Run("ensure only aidl headers are exported", func(t *testing.T) {
- ctx := testCc(t, genRuleModules+`
+ ctx := android.GroupFixturePreparers(
+ prepareForCcTest,
+ aidl_library.PrepareForTestWithAidlLibrary,
+ ).RunTestWithBp(t, `
+ aidl_library {
+ name: "libfoo_aidl",
+ srcs: ["x/y/Bar.aidl"],
+ strip_import_prefix: "x",
+ }
cc_library_shared {
name: "libfoo",
srcs: [
@@ -4588,10 +4780,11 @@
"a.proto",
],
aidl: {
+ libs: ["libfoo_aidl"],
export_aidl_headers: true,
}
}
- `)
+ `).TestContext
foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
checkIncludeDirs(t, ctx, foo,
expectedIncludeDirs(`
@@ -4602,11 +4795,17 @@
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/Bar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/BnBar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/BpBar.h
`),
expectedOrderOnlyDeps(`
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/b.h
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bnb.h
.intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/Bpb.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/Bar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/BnBar.h
+ .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl/y/BpBar.h
`),
)
})
@@ -5101,3 +5300,256 @@
expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
}
+
+func TestDisableSanitizerVariantsInMixedBuilds(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_static {
+ name: "foo_ubsan_minimal",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_ubsan_minimal" },
+ sanitize: {
+ all_undefined: true,
+ integer_overflow: true,
+ },
+ }
+ cc_library_static {
+ name: "foo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo" },
+ sanitize: {
+ address: true,
+ hwaddress: true,
+ fuzzer: true,
+ integer_overflow: true,
+ scs: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_tsan",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_tsan" },
+ sanitize: {
+ thread: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_cfi",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_cfi" },
+ sanitize: {
+ cfi: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_memtag_stack",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_memtag_stack" },
+ sanitize: {
+ memtag_stack: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_memtag_heap",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_memtag_heap" },
+ sanitize: {
+ memtag_heap: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_safestack",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_safestack" },
+ sanitize: {
+ safestack: true,
+ },
+ }
+ cc_library_static {
+ name: "foo_scudo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo_scudo" },
+ sanitize: {
+ scudo: true,
+ },
+ }
+ `
+ testcases := []struct {
+ name string
+ variant string
+ expectedOutputPaths []string
+ }{
+ {
+ name: "foo_ubsan_minimal",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "outputbase/execroot/__main__/foo_ubsan_minimal.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "outputbase/execroot/__main__/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm_armv7-a-neon_static_asan_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_hwasan_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_fuzzer_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_fuzzer_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm_armv7-a-neon_static_asan_fuzzer_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_fuzzer_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_hwasan_fuzzer_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_fuzzer_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_scs_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_scs_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_hwasan_scs_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo",
+ variant: "android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28/foo.a",
+ },
+ },
+ {
+ name: "foo_tsan",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "outputbase/execroot/__main__/foo_tsan.a",
+ },
+ },
+ {
+ name: "foo_tsan",
+ variant: "android_arm64_armv8-a_static_tsan_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_tsan/android_arm64_armv8-a_static_tsan_apex28/foo_tsan.a",
+ },
+ },
+ {
+ name: "foo_cfi",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "outputbase/execroot/__main__/foo_cfi.a",
+ },
+ },
+ {
+ name: "foo_cfi",
+ variant: "android_arm64_armv8-a_static_cfi_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_cfi/android_arm64_armv8-a_static_cfi_apex28/foo_cfi.a",
+ },
+ },
+ {
+ name: "foo_memtag_stack",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_memtag_stack/android_arm64_armv8-a_static_apex28/foo_memtag_stack.a",
+ },
+ },
+ {
+ name: "foo_memtag_heap",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_memtag_heap/android_arm64_armv8-a_static_apex28/foo_memtag_heap.a",
+ },
+ },
+ {
+ name: "foo_safestack",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_safestack/android_arm64_armv8-a_static_apex28/foo_safestack.a",
+ },
+ },
+ {
+ name: "foo_scudo",
+ variant: "android_arm64_armv8-a_static_apex28",
+ expectedOutputPaths: []string{
+ "out/soong/.intermediates/foo_scudo/android_arm64_armv8-a_static_apex28/foo_scudo.a",
+ },
+ },
+ }
+
+ ctx := android.GroupFixturePreparers(
+ prepareForCcTest,
+ prepareForAsanTest,
+ android.FixtureRegisterWithContext(registerTestMutators),
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo_ubsan_minimal": {
+ RootStaticArchives: []string{"foo_ubsan_minimal.a"},
+ },
+ "//foo": {
+ RootStaticArchives: []string{"foo.a"},
+ },
+ "//foo_tsan": {
+ RootStaticArchives: []string{"foo_tsan.a"},
+ },
+ "//foo_cfi": {
+ RootStaticArchives: []string{"foo_cfi.a"},
+ },
+ "//foo_memtag_stack": {
+ RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+ },
+ "//foo_memtag_heap": {
+ RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+ },
+ "//foo_safestack": {
+ RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+ },
+ "//foo_scudo": {
+ RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
+ },
+ },
+ }
+ }),
+ ).RunTestWithBp(t, bp).TestContext
+
+ for _, tc := range testcases {
+ fooMod := ctx.ModuleForTests(tc.name, tc.variant).Module()
+ outputFiles, err := fooMod.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ android.AssertPathsRelativeToTopEquals(t, "output files", tc.expectedOutputPaths, outputFiles)
+ }
+}
diff --git a/cc/compiler.go b/cc/compiler.go
index 88985b6..5da745e 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -120,6 +120,9 @@
Lex *LexProperties
Aidl struct {
+ // List of aidl_library modules
+ Libs []string
+
// list of directories that will be added to the aidl include paths.
Include_dirs []string
@@ -272,6 +275,7 @@
deps.GeneratedSources = append(deps.GeneratedSources, compiler.Properties.Generated_sources...)
deps.GeneratedSources = removeListFromList(deps.GeneratedSources, compiler.Properties.Exclude_generated_sources)
deps.GeneratedHeaders = append(deps.GeneratedHeaders, compiler.Properties.Generated_headers...)
+ deps.AidlLibs = append(deps.AidlLibs, compiler.Properties.Aidl.Libs...)
android.ProtoDeps(ctx, &compiler.Proto)
if compiler.hasSrcExt(".proto") {
@@ -561,7 +565,7 @@
"-I"+android.PathForModuleGen(ctx, "yacc", ctx.ModuleDir()).String())
}
- if compiler.hasSrcExt(".aidl") {
+ if compiler.hasAidl(deps) {
flags.aidlFlags = append(flags.aidlFlags, compiler.Properties.Aidl.Flags...)
if len(compiler.Properties.Aidl.Local_include_dirs) > 0 {
localAidlIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Aidl.Local_include_dirs)
@@ -572,6 +576,14 @@
flags.aidlFlags = append(flags.aidlFlags, includeDirsToFlags(rootAidlIncludeDirs))
}
+ var rootAidlIncludeDirs android.Paths
+ for _, aidlLibraryInfo := range deps.AidlLibraryInfos {
+ rootAidlIncludeDirs = append(rootAidlIncludeDirs, aidlLibraryInfo.IncludeDirs.ToList()...)
+ }
+ if len(rootAidlIncludeDirs) > 0 {
+ flags.aidlFlags = append(flags.aidlFlags, includeDirsToFlags(rootAidlIncludeDirs))
+ }
+
if proptools.BoolDefault(compiler.Properties.Aidl.Generate_traces, true) {
flags.aidlFlags = append(flags.aidlFlags, "-t")
}
@@ -660,6 +672,10 @@
return nil
}
+func (compiler *baseCompiler) hasAidl(deps PathDeps) bool {
+ return len(deps.AidlLibraryInfos) > 0 || compiler.hasSrcExt(".aidl")
+}
+
func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
pathDeps := deps.GeneratedDeps
pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
@@ -668,7 +684,7 @@
srcs := append(android.Paths(nil), compiler.srcsBeforeGen...)
- srcs, genDeps, info := genSources(ctx, srcs, buildFlags)
+ srcs, genDeps, info := genSources(ctx, deps.AidlLibraryInfos, srcs, buildFlags)
pathDeps = append(pathDeps, genDeps...)
compiler.pathDeps = pathDeps
diff --git a/cc/config/global.go b/cc/config/global.go
index a0fe4b7..d63e324 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -354,14 +354,14 @@
// Automatically initialize any uninitialized stack variables.
// Prefer zero-init if multiple options are set.
if ctx.Config().IsEnvTrue("AUTO_ZERO_INITIALIZE") {
- flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -Wno-unused-command-line-argument")
+ flags = append(flags, "-ftrivial-auto-var-init=zero")
} else if ctx.Config().IsEnvTrue("AUTO_PATTERN_INITIALIZE") {
flags = append(flags, "-ftrivial-auto-var-init=pattern")
} else if ctx.Config().IsEnvTrue("AUTO_UNINITIALIZE") {
flags = append(flags, "-ftrivial-auto-var-init=uninitialized")
} else {
// Default to zero initialization.
- flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -Wno-unused-command-line-argument")
+ flags = append(flags, "-ftrivial-auto-var-init=zero")
}
// Workaround for ccache with clang.
@@ -427,14 +427,19 @@
exportedVars.ExportStringList("CommonGlobalIncludes", commonGlobalIncludes)
pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
+ exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion)
+ exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion)
+
pctx.StaticVariableWithEnvOverride("ClangBase", "LLVM_PREBUILTS_BASE", ClangDefaultBase)
- exportedVars.ExportStringStaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
+ pctx.StaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
- exportedVars.ExportStringStaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
+ pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib/clang/${ClangShortVersion}/lib/linux")
+ exportedVars.ExportStringListStaticVariable("WarningAllowedProjects", WarningAllowedProjects)
+
// These are tied to the version of LLVM directly in external/llvm, so they might trail the host prebuilts
// being used for the rest of the build process.
pctx.SourcePathVariable("RSClangBase", "prebuilts/clang/host")
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 7aa8b91..dfefc11 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -103,7 +103,7 @@
*baseCompiler
fuzzPackagedModule fuzz.FuzzPackagedModule
installedSharedDeps []string
- sharedLibraries android.Paths
+ sharedLibraries android.RuleBuilderInstalls
}
func (fuzz *fuzzBinary) fuzzBinary() bool {
@@ -213,19 +213,19 @@
}
func SharedLibraryInstallLocation(
- libraryPath android.Path, isHost bool, fuzzDir string, archString string) string {
+ libraryBase string, isHost bool, fuzzDir string, archString string) string {
installLocation := "$(PRODUCT_OUT)/data"
if isHost {
installLocation = "$(HOST_OUT)"
}
installLocation = filepath.Join(
- installLocation, fuzzDir, archString, "lib", libraryPath.Base())
+ installLocation, fuzzDir, archString, "lib", libraryBase)
return installLocation
}
// Get the device-only shared library symbols install directory.
-func SharedLibrarySymbolsInstallLocation(libraryPath android.Path, fuzzDir string, archString string) string {
- return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryPath.Base())
+func SharedLibrarySymbolsInstallLocation(libraryBase string, fuzzDir string, archString string) string {
+ return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryBase)
}
func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
@@ -242,15 +242,16 @@
// Grab the list of required shared libraries.
fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx)
- for _, lib := range fuzzBin.sharedLibraries {
+ for _, ruleBuilderInstall := range fuzzBin.sharedLibraries {
+ install := ruleBuilderInstall.To
fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
SharedLibraryInstallLocation(
- lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
+ install, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
// Also add the dependency on the shared library symbols dir.
if !ctx.Host() {
fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
- SharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String()))
+ SharedLibrarySymbolsInstallLocation(install, installBase, ctx.Arch().ArchType.String()))
}
}
}
@@ -422,7 +423,7 @@
files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries(), ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
// The executable.
- files = append(files, fuzz.FileToZip{android.OutputFileForModule(ctx, ccModule, "unstripped"), ""})
+ files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")})
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
if !ok {
@@ -453,19 +454,25 @@
// GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for
// packaging.
-func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
+func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
var files []fuzz.FileToZip
fuzzDir := "fuzz"
- for _, library := range sharedLibraries {
- files = append(files, fuzz.FileToZip{library, destinationPathPrefix})
+ for _, ruleBuilderInstall := range sharedLibraries {
+ library := ruleBuilderInstall.From
+ install := ruleBuilderInstall.To
+ files = append(files, fuzz.FileToZip{
+ SourceFilePath: library,
+ DestinationPathPrefix: destinationPathPrefix,
+ DestinationPath: install,
+ })
// For each architecture-specific shared library dependency, we need to
// install it to the output directory. Setup the install destination here,
// which will be used by $(copy-many-files) in the Make backend.
installDestination := SharedLibraryInstallLocation(
- library, module.Host(), fuzzDir, archString)
+ install, module.Host(), fuzzDir, archString)
if (*sharedLibraryInstalled)[installDestination] {
continue
}
@@ -483,7 +490,7 @@
// we want symbolization tools (like `stack`) to be able to find the symbols
// in $ANDROID_PRODUCT_OUT/symbols automagically.
if !module.Host() {
- symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(library, fuzzDir, archString)
+ symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, fuzzDir, archString)
symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
library.String()+":"+symbolsInstallDestination)
@@ -497,12 +504,12 @@
// VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer
// runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies
// have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
-func CollectAllSharedDependencies(ctx android.ModuleContext) (android.Paths, []android.Module) {
+func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.Module) {
seen := make(map[string]bool)
recursed := make(map[string]bool)
deps := []android.Module{}
- var sharedLibraries android.Paths
+ var sharedLibraries android.RuleBuilderInstalls
// Enumerate the first level of dependencies, as we discard all non-library
// modules in the BFS loop below.
@@ -510,22 +517,36 @@
if !IsValidSharedDependency(dep) {
return
}
+ if !ctx.OtherModuleHasProvider(dep, SharedLibraryInfoProvider) {
+ return
+ }
if seen[ctx.OtherModuleName(dep)] {
return
}
seen[ctx.OtherModuleName(dep)] = true
deps = append(deps, dep)
- sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, dep, "unstripped"))
+
+ sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
+ installDestination := sharedLibraryInfo.SharedLibrary.Base()
+ ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, dep, "unstripped"), installDestination}
+ sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
})
ctx.WalkDeps(func(child, parent android.Module) bool {
if !IsValidSharedDependency(child) {
return false
}
+ if !ctx.OtherModuleHasProvider(child, SharedLibraryInfoProvider) {
+ return false
+ }
if !seen[ctx.OtherModuleName(child)] {
seen[ctx.OtherModuleName(child)] = true
deps = append(deps, child)
- sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, child, "unstripped"))
+
+ sharedLibraryInfo := ctx.OtherModuleProvider(child, SharedLibraryInfoProvider).(SharedLibraryInfo)
+ installDestination := sharedLibraryInfo.SharedLibrary.Base()
+ ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination}
+ sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
}
if recursed[ctx.OtherModuleName(child)] {
diff --git a/cc/gen.go b/cc/gen.go
index dfbb177..dbb9560 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -18,7 +18,9 @@
"path/filepath"
"strings"
+ "android/soong/aidl_library"
"android/soong/bazel"
+
"github.com/google/blueprint"
"android/soong/android"
@@ -124,11 +126,6 @@
headerBn := outDir.Join(ctx, aidlPackage, "Bn"+shortName+".h")
headerBp := outDir.Join(ctx, aidlPackage, "Bp"+shortName+".h")
- baseDir := strings.TrimSuffix(aidlFile.String(), aidlFile.Rel())
- if baseDir != "" {
- aidlFlags += " -I" + baseDir
- }
-
cmd := rule.Command()
cmd.BuiltTool("aidl-cpp").
FlagWithDepFile("-d", depFile).
@@ -282,7 +279,10 @@
syspropOrderOnlyDeps android.Paths
}
-func genSources(ctx android.ModuleContext, srcFiles android.Paths,
+func genSources(
+ ctx android.ModuleContext,
+ aidlLibraryInfos []aidl_library.AidlLibraryInfo,
+ srcFiles android.Paths,
buildFlags builderFlags) (android.Paths, android.Paths, generatedSourceInfo) {
var info generatedSourceInfo
@@ -330,7 +330,8 @@
aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
}
- cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags)
+ baseDir := strings.TrimSuffix(srcFile.String(), srcFile.Rel())
+ cppFile, aidlHeaders := genAidl(ctx, aidlRule, srcFile, buildFlags.aidlFlags+" -I"+baseDir)
srcFiles[i] = cppFile
info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
@@ -352,6 +353,24 @@
}
}
+ for _, aidlLibraryInfo := range aidlLibraryInfos {
+ for _, aidlSrc := range aidlLibraryInfo.Srcs {
+ if aidlRule == nil {
+ // TODO(b/279960133): Sandbox inputs to ensure aidl headers are explicitly specified
+ aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
+ android.PathForModuleGen(ctx, "aidl.sbox.textproto"))
+ }
+ cppFile, aidlHeaders := genAidl(ctx, aidlRule, aidlSrc, buildFlags.aidlFlags)
+
+ srcFiles = append(srcFiles, cppFile)
+ info.aidlHeaders = append(info.aidlHeaders, aidlHeaders...)
+ // Use the generated headers as order only deps to ensure that they are up to date when
+ // needed.
+ // TODO: Reduce the size of the ninja file by using one order only dep for the whole rule
+ info.aidlOrderOnlyDeps = append(info.aidlOrderOnlyDeps, aidlHeaders...)
+ }
+ }
+
if aidlRule != nil {
aidlRule.Build("aidl", "gen aidl")
}
diff --git a/cc/library.go b/cc/library.go
index 172ca64..09a7253 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -271,7 +271,9 @@
Implementation_deps bazel.LabelListAttribute
Implementation_dynamic_deps bazel.LabelListAttribute
Tags bazel.StringListAttribute
+
sdkAttributes
+ includesAttributes
}
type stripAttributes struct {
@@ -311,6 +313,11 @@
asFlags = bazel.MakeStringListAttribute(nil)
}
+ sharedFeatures := baseAttributes.features.Clone().Append(sharedAttrs.Features)
+ sharedFeatures.DeduplicateAxesFromBase()
+ staticFeatures := baseAttributes.features.Clone().Append(staticAttrs.Features)
+ staticFeatures.DeduplicateAxesFromBase()
+
staticCommonAttrs := staticOrSharedAttributes{
Srcs: *srcs.Clone().Append(staticAttrs.Srcs),
Srcs_c: *compilerAttrs.cSrcs.Clone().Append(staticAttrs.Srcs_c),
@@ -330,6 +337,14 @@
Native_coverage: baseAttributes.Native_coverage,
}
+ includeAttrs := includesAttributes{
+ Export_includes: exportedIncludes.Includes,
+ Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Local_includes: compilerAttrs.localIncludes,
+ Absolute_includes: compilerAttrs.absoluteIncludes,
+ }
+
sharedCommonAttrs := staticOrSharedAttributes{
Srcs: *srcs.Clone().Append(sharedAttrs.Srcs),
Srcs_c: *compilerAttrs.cSrcs.Clone().Append(sharedAttrs.Srcs_c),
@@ -351,46 +366,39 @@
staticTargetAttrs := &bazelCcLibraryStaticAttributes{
staticOrSharedAttributes: staticCommonAttrs,
+ includesAttributes: includeAttrs,
Cppflags: compilerAttrs.cppFlags,
Conlyflags: compilerAttrs.conlyFlags,
Asflags: asFlags,
- Export_includes: exportedIncludes.Includes,
- Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
- Export_system_includes: exportedIncludes.SystemIncludes,
- Local_includes: compilerAttrs.localIncludes,
- Absolute_includes: compilerAttrs.absoluteIncludes,
- Rtti: compilerAttrs.rtti,
- Stl: compilerAttrs.stl,
- Cpp_std: compilerAttrs.cppStd,
- C_std: compilerAttrs.cStd,
+ Rtti: compilerAttrs.rtti,
+ Stl: compilerAttrs.stl,
+ Cpp_std: compilerAttrs.cppStd,
+ C_std: compilerAttrs.cStd,
- Features: baseAttributes.features,
+ Features: *staticFeatures,
}
sharedTargetAttrs := &bazelCcLibrarySharedAttributes{
staticOrSharedAttributes: sharedCommonAttrs,
- Cppflags: compilerAttrs.cppFlags,
- Conlyflags: compilerAttrs.conlyFlags,
- Asflags: asFlags,
+ includesAttributes: includeAttrs,
- Export_includes: exportedIncludes.Includes,
- Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
- Export_system_includes: exportedIncludes.SystemIncludes,
- Local_includes: compilerAttrs.localIncludes,
- Absolute_includes: compilerAttrs.absoluteIncludes,
- Linkopts: linkerAttrs.linkopts,
- Rtti: compilerAttrs.rtti,
- Stl: compilerAttrs.stl,
- Cpp_std: compilerAttrs.cppStd,
- C_std: compilerAttrs.cStd,
- Use_version_lib: linkerAttrs.useVersionLib,
+ Cppflags: compilerAttrs.cppFlags,
+ Conlyflags: compilerAttrs.conlyFlags,
+ Asflags: asFlags,
+
+ Linkopts: linkerAttrs.linkopts,
+ Rtti: compilerAttrs.rtti,
+ Stl: compilerAttrs.stl,
+ Cpp_std: compilerAttrs.cppStd,
+ C_std: compilerAttrs.cStd,
+ Use_version_lib: linkerAttrs.useVersionLib,
Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
Strip: stripAttrsFromLinkerAttrs(&linkerAttrs),
- Features: baseAttributes.features,
+ Features: *sharedFeatures,
bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, m),
Fdo_profile: compilerAttrs.fdoProfile,
@@ -428,11 +436,11 @@
var tagsForStaticVariant bazel.StringListAttribute
if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 {
- tagsForStaticVariant = android.ApexAvailableTags(m)
+ tagsForStaticVariant = android.ApexAvailableTagsWithoutTestApexes(ctx, m)
}
tagsForStaticVariant.Append(bazel.StringListAttribute{Value: staticAttrs.Apex_available})
- tagsForSharedVariant := android.ApexAvailableTags(m)
+ tagsForSharedVariant := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
tagsForSharedVariant.Append(bazel.StringListAttribute{Value: sharedAttrs.Apex_available})
ctx.CreateBazelTargetModuleWithRestrictions(staticProps,
@@ -931,9 +939,17 @@
func (handler *ccLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
bazelCtx := ctx.Config().BazelContext
bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
+ if v := handler.module.library.stubsVersion(); v != "" {
+ stubsLabel := label + "_stub_libs-" + v
+ bazelCtx.QueueBazelRequest(stubsLabel, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
+ }
}
func (handler *ccLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
+ if v := handler.module.library.stubsVersion(); v != "" {
+ // if we are a stubs variant, just use the Bazel stubs target
+ label = label + "_stub_libs-" + v
+ }
bazelCtx := ctx.Config().BazelContext
ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
if err != nil {
@@ -962,6 +978,9 @@
}
handler.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo)
+
+ cctx := moduleContextFromAndroidModuleContext(ctx, handler.module)
+ addStubDependencyProviders(cctx)
}
func (library *libraryDecorator) setFlagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) {
@@ -1787,6 +1806,12 @@
Target: ctx.Target(),
})
+ addStubDependencyProviders(ctx)
+
+ return unstrippedOutputFile
+}
+
+func addStubDependencyProviders(ctx ModuleContext) {
stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
if len(stubs) > 0 {
var stubsInfo []SharedStubLibrary
@@ -1801,12 +1826,9 @@
}
ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
SharedStubLibraries: stubsInfo,
-
- IsLLNDK: ctx.IsLlndk(),
+ IsLLNDK: ctx.IsLlndk(),
})
}
-
- return unstrippedOutputFile
}
func (library *libraryDecorator) unstrippedOutputFilePath() android.Path {
@@ -2095,7 +2117,7 @@
// Optionally export aidl headers.
if Bool(library.Properties.Aidl.Export_aidl_headers) {
- if library.baseCompiler.hasSrcExt(".aidl") {
+ if library.baseCompiler.hasAidl(deps) {
dir := android.PathForModuleGen(ctx, "aidl")
library.reexportDirs(dir)
@@ -2392,7 +2414,10 @@
}
// Future API level is implicitly added if there isn't
- vers := library.Properties.Stubs.Versions
+ return addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+}
+
+func addCurrentVersionIfNotPresent(vers []string) []string {
if inList(android.FutureApiLevel.String(), vers) {
return vers
}
@@ -2657,7 +2682,7 @@
// normalizeVersions modifies `versions` in place, so that each raw version
// string becomes its normalized canonical form.
// Validates that the versions in `versions` are specified in least to greatest order.
-func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
+func normalizeVersions(ctx android.BazelConversionPathContext, versions []string) {
var previous android.ApiLevel
for i, v := range versions {
ver, err := android.ApiLevelFromUser(ctx, v)
@@ -2858,6 +2883,13 @@
linkerAttrs := baseAttributes.linkerAttributes
exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &compilerAttrs.includes)
+ includeAttrs := includesAttributes{
+ Export_includes: exportedIncludes.Includes,
+ Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Local_includes: compilerAttrs.localIncludes,
+ Absolute_includes: compilerAttrs.absoluteIncludes,
+ }
// Append shared/static{} stanza properties. These won't be specified on
// cc_library_* itself, but may be specified in cc_defaults that this module
@@ -2881,6 +2913,9 @@
asFlags = bazel.MakeStringListAttribute(nil)
}
+ features := baseAttributes.features.Clone().Append(libSharedOrStaticAttrs.Features)
+ features.DeduplicateAxesFromBase()
+
commonAttrs := staticOrSharedAttributes{
Srcs: compilerAttrs.srcs,
Srcs_c: compilerAttrs.cSrcs,
@@ -2912,17 +2947,13 @@
Cpp_std: compilerAttrs.cppStd,
C_std: compilerAttrs.cStd,
- Export_includes: exportedIncludes.Includes,
- Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
- Export_system_includes: exportedIncludes.SystemIncludes,
- Local_includes: compilerAttrs.localIncludes,
- Absolute_includes: compilerAttrs.absoluteIncludes,
+ includesAttributes: includeAttrs,
Cppflags: compilerAttrs.cppFlags,
Conlyflags: compilerAttrs.conlyFlags,
Asflags: asFlags,
- Features: baseAttributes.features,
+ Features: *features,
}
} else {
commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
@@ -2942,16 +2973,13 @@
Cpp_std: compilerAttrs.cppStd,
C_std: compilerAttrs.cStd,
- Export_includes: exportedIncludes.Includes,
- Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
- Export_system_includes: exportedIncludes.SystemIncludes,
- Local_includes: compilerAttrs.localIncludes,
- Absolute_includes: compilerAttrs.absoluteIncludes,
+ includesAttributes: includeAttrs,
+
Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
Strip: stripAttrsFromLinkerAttrs(&linkerAttrs),
- Features: baseAttributes.features,
+ Features: *features,
Suffix: compilerAttrs.suffix,
@@ -2977,14 +3005,23 @@
Bzl_load_location: fmt.Sprintf("//build/bazel/rules/cc:%s.bzl", modType),
}
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name(), Tags: tags}, attrs)
}
+type includesAttributes struct {
+ Export_includes bazel.StringListAttribute
+ Export_absolute_includes bazel.StringListAttribute
+ Export_system_includes bazel.StringListAttribute
+ Local_includes bazel.StringListAttribute
+ Absolute_includes bazel.StringListAttribute
+}
+
// TODO(b/199902614): Can this be factored to share with the other Attributes?
type bazelCcLibraryStaticAttributes struct {
staticOrSharedAttributes
+ includesAttributes
Use_version_lib bazel.BoolAttribute
Rtti bazel.BoolAttribute
@@ -2992,12 +3029,7 @@
Cpp_std *string
C_std *string
- Export_includes bazel.StringListAttribute
- Export_absolute_includes bazel.StringListAttribute
- Export_system_includes bazel.StringListAttribute
- Local_includes bazel.StringListAttribute
- Absolute_includes bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
Cppflags bazel.StringListAttribute
Conlyflags bazel.StringListAttribute
@@ -3009,6 +3041,7 @@
// TODO(b/199902614): Can this be factored to share with the other Attributes?
type bazelCcLibrarySharedAttributes struct {
staticOrSharedAttributes
+ includesAttributes
Linkopts bazel.StringListAttribute
Use_version_lib bazel.BoolAttribute
@@ -3018,12 +3051,7 @@
Cpp_std *string
C_std *string
- Export_includes bazel.StringListAttribute
- Export_absolute_includes bazel.StringListAttribute
- Export_system_includes bazel.StringListAttribute
- Local_includes bazel.StringListAttribute
- Absolute_includes bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
Strip stripAttributes
Additional_linker_inputs bazel.LabelListAttribute
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 1dee726..ce9c4aa 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -151,7 +151,7 @@
Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
}
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{
Name: module.Name(),
diff --git a/cc/linkable.go b/cc/linkable.go
index 9578807..557f5d2 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -130,7 +130,7 @@
// FuzzSharedLibraries returns the shared library dependencies for this module.
// Expects that IsFuzzModule returns true.
- FuzzSharedLibraries() android.Paths
+ FuzzSharedLibraries() android.RuleBuilderInstalls
Device() bool
Host() bool
diff --git a/cc/object.go b/cc/object.go
index d65cdea..ca14845 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -226,7 +226,7 @@
Bzl_load_location: "//build/bazel/rules/cc:cc_object.bzl",
}
- tags := android.ApexAvailableTags(m)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{
Name: m.Name(),
@@ -309,6 +309,8 @@
})
}
} else {
+ outputAddrSig := android.PathForModuleOut(ctx, "addrsig", outputName)
+
if String(object.Properties.Prefix_symbols) != "" {
input := android.PathForModuleOut(ctx, "unprefixed", outputName)
transformBinaryPrefixSymbols(ctx, String(object.Properties.Prefix_symbols), input,
@@ -316,7 +318,12 @@
output = input
}
- transformObjsToObj(ctx, objs.objFiles, builderFlags, output, flags.LdFlagsDeps)
+ transformObjsToObj(ctx, objs.objFiles, builderFlags, outputAddrSig, flags.LdFlagsDeps)
+
+ // ld -r reorders symbols and invalidates the .llvm_addrsig section, which then causes warnings
+ // if the resulting object is used with ld --icf=safe. Strip the .llvm_addrsig section to
+ // prevent the warnings.
+ transformObjectNoAddrSig(ctx, outputAddrSig, output)
}
ctx.CheckbuildFile(outputFile)
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 0b5841e..44cd0d7 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -389,7 +389,7 @@
name += "_bp2build_cc_library_static"
}
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
_true := true
@@ -420,7 +420,7 @@
}
name := android.RemoveOptionalPrebuiltPrefix(module.Name())
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
}
@@ -650,7 +650,7 @@
}
name := android.RemoveOptionalPrebuiltPrefix(module.Name())
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs)
}
@@ -813,7 +813,7 @@
}
name := android.RemoveOptionalPrebuiltPrefix(module.Name())
- tags := android.ApexAvailableTags(module)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs)
}
diff --git a/cc/proto.go b/cc/proto.go
index 97470e5..5d9aef6 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -207,7 +207,7 @@
protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version
name := m.Name() + suffix
- tags := android.ApexAvailableTags(m)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), m)
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: rule_class,
diff --git a/cc/sdk.go b/cc/sdk.go
index 4f361eb..6341926 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -47,16 +47,16 @@
// Mark the SDK variant.
modules[1].(*Module).Properties.IsSdkVariant = true
- // SDK variant is not supposed to be installed
- modules[1].(*Module).Properties.PreventInstall = true
if ctx.Config().UnbundledBuildApps() {
// For an unbundled apps build, hide the platform variant from Make.
modules[0].(*Module).Properties.HideFromMake = true
+ modules[0].(*Module).Properties.PreventInstall = true
} else {
// For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
// exposed to Make.
modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
+ modules[1].(*Module).Properties.PreventInstall = true
}
ctx.AliasVariation("")
} else if isCcModule && ccModule.isImportedApiLibrary() {
@@ -74,8 +74,8 @@
if apiLibrary.hasApexStubs() {
// For an unbundled apps build, hide the platform variant from Make.
modules[1].(*Module).Properties.HideFromMake = true
- modules[1].(*Module).Properties.PreventInstall = true
}
+ modules[1].(*Module).Properties.PreventInstall = true
} else {
// For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
// exposed to Make.
diff --git a/cc/sdk_test.go b/cc/sdk_test.go
index 790440c..61925e3 100644
--- a/cc/sdk_test.go
+++ b/cc/sdk_test.go
@@ -101,95 +101,3 @@
assertDep(t, libsdkNDK, libcxxNDK)
assertDep(t, libsdkPlatform, libcxxPlatform)
}
-
-func TestMakeModuleNameForSdkVariant(t *testing.T) {
- bp := `
- cc_library {
- name: "libfoo",
- srcs: ["main_test.cpp"],
- sdk_version: "current",
- stl: "none",
- }
- `
- platformVariant := "android_arm64_armv8-a_shared"
- sdkVariant := "android_arm64_armv8-a_sdk_shared"
- testCases := []struct {
- name string
- unbundledApps []string
- variant string
- skipInstall bool // soong skips install
- hideFromMake bool // no make entry
- makeUninstallable bool // make skips install
- makeModuleName string
- }{
- {
- name: "platform variant in normal builds",
- unbundledApps: nil,
- variant: platformVariant,
- // installable in soong
- skipInstall: false,
- // visiable in Make as "libfoo"
- hideFromMake: false,
- makeModuleName: "libfoo",
- // installable in Make
- makeUninstallable: false,
- },
- {
- name: "sdk variant in normal builds",
- unbundledApps: nil,
- variant: sdkVariant,
- // soong doesn't install
- skipInstall: true,
- // visible in Make as "libfoo.sdk"
- hideFromMake: false,
- makeModuleName: "libfoo.sdk",
- // but not installed
- makeUninstallable: true,
- },
- {
- name: "platform variant in unbunded builds",
- unbundledApps: []string{"bar"},
- variant: platformVariant,
- // installable in soong
- skipInstall: false,
- // hidden from make
- hideFromMake: true,
- },
- {
- name: "sdk variant in unbunded builds",
- unbundledApps: []string{"bar"},
- variant: sdkVariant,
- // soong doesn't install
- skipInstall: true,
- // visible in Make as "libfoo"
- hideFromMake: false,
- makeModuleName: "libfoo",
- // but not installed
- makeUninstallable: true,
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- fixture := android.GroupFixturePreparers(prepareForCcTest,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.Unbundled_build_apps = tc.unbundledApps
- }),
- )
- ctx := fixture.RunTestWithBp(t, bp).TestContext
- module := ctx.ModuleForTests("libfoo", tc.variant).Module().(*Module)
- android.AssertBoolEquals(t, "IsSkipInstall", tc.skipInstall, module.IsSkipInstall())
- android.AssertBoolEquals(t, "HideFromMake", tc.hideFromMake, module.HiddenFromMake())
- if !tc.hideFromMake {
- entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
- android.AssertStringEquals(t, "LOCAL_MODULE",
- tc.makeModuleName, entries.EntryMap["LOCAL_MODULE"][0])
- actualUninstallable := false
- if actual, ok := entries.EntryMap["LOCAL_UNINSTALLABLE_MODULE"]; ok {
- actualUninstallable = "true" == actual[0]
- }
- android.AssertBoolEquals(t, "LOCAL_UNINSTALLABLE_MODULE",
- tc.makeUninstallable, actualUninstallable)
- }
- })
- }
-}
diff --git a/cc/sysprop.go b/cc/sysprop.go
index 0df290a..7ddd476 100644
--- a/cc/sysprop.go
+++ b/cc/sysprop.go
@@ -38,7 +38,7 @@
}
func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) {
- apexAvailableTags := android.ApexAvailableTags(ctx.Module())
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: "sysprop_library",
diff --git a/cc/testing.go b/cc/testing.go
index ced0929..d346739 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -82,6 +82,10 @@
sanitize: {
never: true,
},
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
}
cc_prebuilt_library_static {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 2c35d76..cf6c1c7 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -30,6 +30,7 @@
"android/soong/shared"
"android/soong/ui/metrics/bp2build_metrics_proto"
+ "github.com/google/blueprint"
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/deptools"
"github.com/google/blueprint/metrics"
@@ -85,7 +86,7 @@
flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses")
flag.BoolVar(&cmdlineArgs.BuildFromTextStub, "build-from-text-stub", false, "build Java stubs from API text files instead of source files")
-
+ flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
// Flags that probably shouldn't be flags of soong_build, but we haven't found
// the time to remove them yet
flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
@@ -132,6 +133,10 @@
ninjaDeps = append(ninjaDeps, writeBuildGlobsNinjaFile(ctx)...)
writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
+
+ if ctx.Config().IsEnvTrue("SOONG_GENERATES_NINJA_HINT") {
+ writeNinjaHint(ctx)
+ }
return cmdlineArgs.OutFile
}
@@ -256,18 +261,47 @@
}
func writeNinjaHint(ctx *android.Context) error {
- wantModules := make([]string, len(allowlists.HugeModulesMap))
- i := 0
- for k := range allowlists.HugeModulesMap {
- wantModules[i] = k
- i += 1
- }
- outputsMap := ctx.Context.GetOutputsFromModuleNames(wantModules)
- var outputBuilder strings.Builder
- for k, v := range allowlists.HugeModulesMap {
- for _, output := range outputsMap[k] {
- outputBuilder.WriteString(fmt.Sprintf("%s,%d\n", output, v))
+ ctx.BeginEvent("ninja_hint")
+ defer ctx.EndEvent("ninja_hint")
+ // The current predictor focuses on reducing false negatives.
+ // If there are too many false positives (e.g., most modules are marked as positive),
+ // real long-running jobs cannot run early.
+ // Therefore, the model should be adjusted in this case.
+ // The model should also be adjusted if there are critical false negatives.
+ predicate := func(j *blueprint.JsonModule) (prioritized bool, weight int) {
+ prioritized = false
+ weight = 0
+ for prefix, w := range allowlists.HugeModuleTypePrefixMap {
+ if strings.HasPrefix(j.Type, prefix) {
+ prioritized = true
+ weight = w
+ return
+ }
}
+ dep_count := len(j.Deps)
+ src_count := 0
+ for _, a := range j.Module["Actions"].([]blueprint.JSONAction) {
+ src_count += len(a.Inputs)
+ }
+ input_size := dep_count + src_count
+
+ // Current threshold is an arbitrary value which only consider recall rather than accuracy.
+ if input_size > allowlists.INPUT_SIZE_THRESHOLD {
+ prioritized = true
+ weight += ((input_size) / allowlists.INPUT_SIZE_THRESHOLD) * allowlists.DEFAULT_PRIORITIZED_WEIGHT
+
+ // To prevent some modules from having too large a priority value.
+ if weight > allowlists.HIGH_PRIORITIZED_WEIGHT {
+ weight = allowlists.HIGH_PRIORITIZED_WEIGHT
+ }
+ }
+ return
+ }
+
+ outputsMap := ctx.Context.GetWeightedOutputsFromPredicate(predicate)
+ var outputBuilder strings.Builder
+ for output, weight := range outputsMap {
+ outputBuilder.WriteString(fmt.Sprintf("%s,%d\n", output, weight))
}
weightListFile := filepath.Join(topDir, ctx.Config().OutDir(), ".ninja_weight_list")
@@ -288,6 +322,67 @@
maybeQuit(err, "error writing soong_build metrics %s", metricsFile)
}
+// Errors out if any modules expected to be mixed_built were not, unless
+// the modules did not exist.
+func checkForAllowlistIntegrityError(configuration android.Config, isStagingMode bool) error {
+ modules := findMisconfiguredModules(configuration, isStagingMode)
+ if len(modules) == 0 {
+ return nil
+ }
+
+ return fmt.Errorf("Error: expected the following modules to be mixed_built: %s", modules)
+}
+
+// Returns true if the given module has all of the following true:
+// 1. Is allowlisted to be built with Bazel.
+// 2. Has a variant which is *not* built with Bazel.
+// 3. Has no variant which is built with Bazel.
+//
+// This indicates the allowlisting of this variant had no effect.
+// TODO(b/280457637): Return true for nonexistent modules.
+func isAllowlistMisconfiguredForModule(module string, mixedBuildsEnabled map[string]struct{}, mixedBuildsDisabled map[string]struct{}) bool {
+ _, enabled := mixedBuildsEnabled[module]
+
+ if enabled {
+ return false
+ }
+
+ _, disabled := mixedBuildsDisabled[module]
+ return disabled
+
+}
+
+// Returns the list of modules that should have been mixed_built (per the
+// allowlists and cmdline flags) but were not.
+// Note: nonexistent modules are excluded from the list. See b/280457637
+func findMisconfiguredModules(configuration android.Config, isStagingMode bool) []string {
+ retval := []string{}
+ forceEnabledModules := configuration.BazelModulesForceEnabledByFlag()
+
+ mixedBuildsEnabled := configuration.GetMixedBuildsEnabledModules()
+ mixedBuildsDisabled := configuration.GetMixedBuildsDisabledModules()
+ for _, module := range allowlists.ProdMixedBuildsEnabledList {
+ if isAllowlistMisconfiguredForModule(module, mixedBuildsEnabled, mixedBuildsDisabled) {
+ retval = append(retval, module)
+ }
+ }
+
+ if isStagingMode {
+ for _, module := range allowlists.StagingMixedBuildsEnabledList {
+ if isAllowlistMisconfiguredForModule(module, mixedBuildsEnabled, mixedBuildsDisabled) {
+ retval = append(retval, module)
+ }
+ }
+ }
+
+ for module, _ := range forceEnabledModules {
+ if isAllowlistMisconfiguredForModule(module, mixedBuildsEnabled, mixedBuildsDisabled) {
+ retval = append(retval, module)
+ }
+ }
+ return retval
+}
+
func writeJsonModuleGraphAndActions(ctx *android.Context, cmdArgs android.CmdArgs) {
graphFile, graphErr := os.Create(shared.JoinPath(topDir, cmdArgs.ModuleGraphFile))
maybeQuit(graphErr, "graph err")
@@ -364,6 +459,9 @@
// The actual output (build.ninja) was written in the RunBlueprint() call
// above
writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
+ if ctx.Config().IsEnvTrue("SOONG_GENERATES_NINJA_HINT") {
+ writeNinjaHint(ctx)
+ }
return cmdlineArgs.OutFile
}
}
@@ -433,14 +531,17 @@
writeMetrics(configuration, ctx.EventHandler, metricsDir)
default:
ctx.Register()
- if configuration.IsMixedBuildsEnabled() {
+ isMixedBuildsEnabled := configuration.IsMixedBuildsEnabled()
+ if isMixedBuildsEnabled {
finalOutputFile = runMixedModeBuild(ctx, extraNinjaDeps)
+ if cmdlineArgs.EnsureAllowlistIntegrity {
+ if err := checkForAllowlistIntegrityError(configuration, cmdlineArgs.BazelModeStaging); err != nil {
+ maybeQuit(err, "")
+ }
+ }
} else {
finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
}
- if ctx.Config().IsEnvTrue("SOONG_GENERATES_NINJA_HINT") {
- writeNinjaHint(ctx)
- }
writeMetrics(configuration, ctx.EventHandler, metricsDir)
}
writeUsedEnvironmentFile(configuration)
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index ce32184..67cb6cf 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -15,6 +15,7 @@
package main
import (
+ "android/soong/starlark_import"
"io/fs"
"io/ioutil"
"os"
@@ -47,6 +48,14 @@
}
}
+ // Add starlark deps here, so that they apply to both queryview and apibp2build which
+ // both run this function.
+ starlarkDeps, err2 := starlark_import.GetNinjaDeps()
+ if err2 != nil {
+ return err2
+ }
+ ctx.AddNinjaFileDeps(starlarkDeps...)
+
return nil
}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 301246a..eea41e6 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -92,14 +92,13 @@
stdio: stdio,
run: runMake,
}, {
- flag: "--upload-metrics-only",
- description: "upload metrics without building anything",
- config: uploadOnlyConfig,
+ flag: "--finalize-bazel-metrics",
+ description: "finalize b metrics and upload",
+ config: build.UploadOnlyConfig,
stdio: stdio,
- // Upload-only mode mostly skips to the metrics-uploading phase of soong_ui.
- // However, this invocation marks the true "end of the build", and thus we
- // need to update the total runtime of the build to include this upload step.
- run: updateTotalRealTime,
+ // Finalize-bazel-metrics mode updates metrics files and calls the metrics
+ // uploader. This marks the end of a b invocation.
+ run: finalizeBazelMetrics,
},
}
@@ -203,8 +202,6 @@
bazelMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bazel_metrics.pb")
soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
- //the profile file generated by Bazel"
- bazelProfileFile := filepath.Join(logsDir, c.logsPrefix+"analyzed_bazel_profile.txt")
metricsFiles := []string{
buildErrorFile, // build error strings
rbeMetricsFile, // high level metrics related to remote build execution.
@@ -226,7 +223,7 @@
criticalPath.WriteToMetrics(met)
met.Dump(soongMetricsFile)
if !config.SkipMetricsUpload() {
- build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, bazelProfileFile, bazelMetricsFile, metricsFiles...)
+ build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, metricsFiles...)
}
}()
c.run(buildCtx, config, args)
@@ -451,14 +448,6 @@
return build.NewConfig(ctx)
}
-// uploadOnlyConfig explicitly requires no arguments.
-func uploadOnlyConfig(ctx build.Context, args ...string) build.Config {
- if len(args) > 0 {
- fmt.Printf("--upload-only does not require arguments.")
- }
- return build.UploadOnlyConfig(ctx)
-}
-
func buildActionConfig(ctx build.Context, args ...string) build.Config {
flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
flags.SetOutput(ctx.Writer)
@@ -700,6 +689,15 @@
}
}
+func finalizeBazelMetrics(ctx build.Context, config build.Config, args []string) {
+ updateTotalRealTime(ctx, config, args)
+
+ logsDir := config.LogsDir()
+ logsPrefix := config.GetLogsPrefix()
+ bazelMetricsFile := filepath.Join(logsDir, logsPrefix+"bazel_metrics.pb")
+ bazelProfileFile := filepath.Join(logsDir, logsPrefix+"analyzed_bazel_profile.txt")
+ build.ProcessBazelMetrics(bazelProfileFile, bazelMetricsFile, ctx, config)
+}
func updateTotalRealTime(ctx build.Context, config build.Config, args []string) {
soongMetricsFile := filepath.Join(config.LogsDir(), "soong_metrics")
@@ -710,7 +708,7 @@
}
met := ctx.ContextImpl.Metrics
- err = met.UpdateTotalRealTime(data)
+ err = met.UpdateTotalRealTimeAndNonZeroExit(data, config.BazelExitCode())
if err != nil {
ctx.Fatal(err)
}
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index 491267b..5ab9656 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -128,12 +128,6 @@
}
for _, arg := range args {
- // Reserve escaping for future implementation, so make sure no
- // one is using \ and expecting a certain behavior.
- if strings.Contains(arg, "\\") {
- return fmt.Errorf("\\ characters are not currently supported")
- }
-
input, output := includeSplit(arg)
var includeMatches []pair
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index 2c4e005..c238098 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -38,13 +38,6 @@
storedFiles []string
err error
}{
- {
- name: "unsupported \\",
-
- args: []string{"a\\b:b"},
-
- err: fmt.Errorf("\\ characters are not currently supported"),
- },
{ // This is modelled after the update package build rules in build/make/core/Makefile
name: "filter globs",
@@ -406,6 +399,13 @@
"b/a/b",
},
},
+ {
+ name: "escaping",
+
+ inputFiles: []string{"a"},
+ args: []string{"\\a"},
+ outputFiles: []string{"a"},
+ },
}
func errorString(e error) string {
diff --git a/device_config/Android.bp b/device_config/Android.bp
new file mode 100644
index 0000000..360b389
--- /dev/null
+++ b/device_config/Android.bp
@@ -0,0 +1,30 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-device_config",
+ pkgPath: "android/soong/device_config",
+ deps: [
+ "blueprint",
+ "blueprint-pathtools",
+ "sbox_proto",
+ "soong",
+ "soong-android",
+ "soong-bazel",
+ "soong-shared",
+ ],
+ srcs: [
+ "device_config_definitions.go",
+ "device_config_values.go",
+ "device_config_value_set.go",
+ "init.go",
+ //"testing.go"
+ ],
+ /*
+ testSrcs: [
+ "device_config_test.go",
+ ],
+ */
+ pluginFor: ["soong_build"],
+}
diff --git a/device_config/device_config_definitions.go b/device_config/device_config_definitions.go
new file mode 100644
index 0000000..c565766
--- /dev/null
+++ b/device_config/device_config_definitions.go
@@ -0,0 +1,150 @@
+// Copyright 2023 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 device_config
+
+import (
+ "android/soong/android"
+ "fmt"
+ "github.com/google/blueprint"
+ "strings"
+)
+
+type DefinitionsModule struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ // Properties for "device_config_definitions"
+ properties struct {
+ // aconfig files, relative to this Android.bp file
+ Srcs []string `android:"path"`
+
+ // Release config flag namespace
+ Namespace string
+
+ // Values from TARGET_RELEASE / RELEASE_DEVICE_CONFIG_VALUE_SETS
+ Values []string `blueprint:"mutated"`
+ }
+
+ intermediatePath android.WritablePath
+ srcJarPath android.WritablePath
+}
+
+func DefinitionsFactory() android.Module {
+ module := &DefinitionsModule{}
+
+ android.InitAndroidModule(module)
+ android.InitDefaultableModule(module)
+ module.AddProperties(&module.properties)
+ // TODO: bp2build
+ //android.InitBazelModule(module)
+
+ return module
+}
+
+type implicitValuesTagType struct {
+ blueprint.BaseDependencyTag
+}
+
+var implicitValuesTag = implicitValuesTagType{}
+
+func (module *DefinitionsModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Validate Properties
+ if len(module.properties.Srcs) == 0 {
+ ctx.PropertyErrorf("srcs", "missing source files")
+ return
+ }
+ if len(module.properties.Namespace) == 0 {
+ ctx.PropertyErrorf("namespace", "missing namespace property")
+ }
+
+ // Add a dependency on the device_config_value_sets defined in
+ // RELEASE_DEVICE_CONFIG_VALUE_SETS, and add any device_config_values that
+ // match our namespace.
+ valuesFromConfig := ctx.Config().ReleaseDeviceConfigValueSets()
+ ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig...)
+}
+
+func (module *DefinitionsModule) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case ".srcjar":
+ return []android.Path{module.srcJarPath}, nil
+ case "":
+ // The default output of this module is the intermediates format, which is
+ // not installable and in a private format that no other rules can handle
+ // correctly.
+ return []android.Path{module.intermediatePath}, nil
+ default:
+ return nil, fmt.Errorf("unsupported device_config_definitions module reference tag %q", tag)
+ }
+}
+
+func joinAndPrefix(prefix string, values []string) string {
+ var sb strings.Builder
+ for _, v := range values {
+ sb.WriteString(prefix)
+ sb.WriteString(v)
+ }
+ return sb.String()
+}
+
+func (module *DefinitionsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Get the values that came from the global RELEASE_DEVICE_CONFIG_VALUE_SETS flag
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if !ctx.OtherModuleHasProvider(dep, valueSetProviderKey) {
+ // Other modules get injected as dependencies too, for example the license modules
+ return
+ }
+ depData := ctx.OtherModuleProvider(dep, valueSetProviderKey).(valueSetProviderData)
+ valuesFiles, ok := depData.AvailableNamespaces[module.properties.Namespace]
+ if ok {
+ for _, path := range valuesFiles {
+ module.properties.Values = append(module.properties.Values, path.String())
+ }
+ }
+ })
+
+ // Intermediate format
+ inputFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
+ module.intermediatePath = android.PathForModuleOut(ctx, "intermediate.json")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: aconfigRule,
+ Inputs: inputFiles,
+ Output: module.intermediatePath,
+ Description: "device_config_definitions",
+ Args: map[string]string{
+ "release_version": ctx.Config().ReleaseVersion(),
+ "namespace": module.properties.Namespace,
+ "values": joinAndPrefix(" --values ", module.properties.Values),
+ },
+ })
+
+ // Generated java inside a srcjar
+ module.srcJarPath = android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: srcJarRule,
+ Input: module.intermediatePath,
+ Output: module.srcJarPath,
+ Description: "device_config.srcjar",
+ })
+
+ // TODO: C++
+
+ // Phony target for debugging convenience
+ ctx.Build(pctx, android.BuildParams{
+ Rule: blueprint.Phony,
+ Output: android.PathForPhony(ctx, ctx.ModuleName()),
+ Inputs: []android.Path{module.srcJarPath}, // TODO: C++
+ })
+}
diff --git a/device_config/device_config_test.go b/device_config/device_config_test.go
new file mode 100644
index 0000000..91a06a7
--- /dev/null
+++ b/device_config/device_config_test.go
@@ -0,0 +1,61 @@
+// Copyright (C) 2019 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 device_config
+
+import (
+ "os"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/java"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(m.Run())
+}
+
+func test(t *testing.T, bp string) *android.TestResult {
+ t.Helper()
+
+ mockFS := android.MockFS{
+ "config.aconfig": nil,
+ }
+
+ result := android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithSyspropBuildComponents,
+ // TODO: Consider values files, although maybe in its own test
+ // android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ // variables.ReleaseConfigValuesBasePaths = ...
+ //})
+ mockFS.AddToFixture(),
+ android.FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ return result
+}
+
+func TestOutputs(t *testing.T) {
+ /*result := */ test(t, `
+ device_config {
+ name: "my_device_config",
+ srcs: ["config.aconfig"],
+ }
+ `)
+
+ // TODO: Make sure it exports a .srcjar, which is used by java libraries
+ // TODO: Make sure it exports an intermediates file
+ // TODO: Make sure the intermediates file is propagated to the Android.mk file
+}
diff --git a/device_config/device_config_value_set.go b/device_config/device_config_value_set.go
new file mode 100644
index 0000000..e406d20
--- /dev/null
+++ b/device_config/device_config_value_set.go
@@ -0,0 +1,92 @@
+// Copyright 2023 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 device_config
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+// Properties for "device_config_value_set"
+type ValueSetModule struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ properties struct {
+ // device_config_values modules
+ Values []string
+ }
+}
+
+func ValueSetFactory() android.Module {
+ module := &ValueSetModule{}
+
+ android.InitAndroidModule(module)
+ android.InitDefaultableModule(module)
+ module.AddProperties(&module.properties)
+ // TODO: bp2build
+ //android.InitBazelModule(module)
+
+ return module
+}
+
+// Dependency tag for values property
+type valueSetType struct {
+ blueprint.BaseDependencyTag
+}
+
+var valueSetTag = valueSetType{}
+
+// Provider published by device_config_value_set
+type valueSetProviderData struct {
+ // The namespace of each of the
+ // (map of namespace --> device_config_module)
+ AvailableNamespaces map[string]android.Paths
+}
+
+var valueSetProviderKey = blueprint.NewProvider(valueSetProviderData{})
+
+func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...)
+ for _, dep := range deps {
+ _, ok := dep.(*ValuesModule)
+ if !ok {
+ ctx.PropertyErrorf("values", "values must be a device_config_values module")
+ return
+ }
+ }
+}
+
+func (module *ValueSetModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Accumulate the namespaces of the values modules listed, and set that as an
+ // valueSetProviderKey provider that device_config modules can read and use
+ // to append values to their aconfig actions.
+ namespaces := make(map[string]android.Paths)
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ if !ctx.OtherModuleHasProvider(dep, valuesProviderKey) {
+ // Other modules get injected as dependencies too, for example the license modules
+ return
+ }
+ depData := ctx.OtherModuleProvider(dep, valuesProviderKey).(valuesProviderData)
+
+ srcs := make([]android.Path, len(depData.Values))
+ copy(srcs, depData.Values)
+ namespaces[depData.Namespace] = srcs
+
+ })
+ ctx.SetProvider(valueSetProviderKey, valueSetProviderData{
+ AvailableNamespaces: namespaces,
+ })
+}
diff --git a/device_config/device_config_values.go b/device_config/device_config_values.go
new file mode 100644
index 0000000..110f12a
--- /dev/null
+++ b/device_config/device_config_values.go
@@ -0,0 +1,70 @@
+// Copyright 2023 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 device_config
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+// Properties for "device_config_value"
+type ValuesModule struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ properties struct {
+ // aconfig files, relative to this Android.bp file
+ Srcs []string `android:"path"`
+
+ // Release config flag namespace
+ Namespace string
+ }
+}
+
+func ValuesFactory() android.Module {
+ module := &ValuesModule{}
+
+ android.InitAndroidModule(module)
+ android.InitDefaultableModule(module)
+ module.AddProperties(&module.properties)
+ // TODO: bp2build
+ //android.InitBazelModule(module)
+
+ return module
+}
+
+// Provider published by device_config_value_set
+type valuesProviderData struct {
+ // The namespace that this values module values
+ Namespace string
+
+ // The values aconfig files, relative to the root of the tree
+ Values android.Paths
+}
+
+var valuesProviderKey = blueprint.NewProvider(valuesProviderData{})
+
+func (module *ValuesModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if len(module.properties.Namespace) == 0 {
+ ctx.PropertyErrorf("namespace", "missing namespace property")
+ }
+
+ // Provide the our source files list to the device_config_value_set as a list of files
+ providerData := valuesProviderData{
+ Namespace: module.properties.Namespace,
+ Values: android.PathsForModuleSrc(ctx, module.properties.Srcs),
+ }
+ ctx.SetProvider(valuesProviderKey, providerData)
+}
diff --git a/device_config/init.go b/device_config/init.go
new file mode 100644
index 0000000..0a4645b
--- /dev/null
+++ b/device_config/init.go
@@ -0,0 +1,70 @@
+// Copyright 2023 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 device_config
+
+import (
+ "android/soong/android"
+ "github.com/google/blueprint"
+)
+
+var (
+ pctx = android.NewPackageContext("android/soong/device_config")
+
+ // For device_config_definitions: Generate cache file
+ // TODO: Restat
+ aconfigRule = pctx.AndroidStaticRule("aconfig",
+ blueprint.RuleParams{
+ Command: `${aconfig} create-cache` +
+ ` --namespace ${namespace}` +
+ ` --declarations ${in}` +
+ ` ${values}` +
+ ` --cache ${out}.tmp` +
+ ` && ( if cmp -s ${out}.tmp ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
+ // ` --build-id ${release_version}` +
+ CommandDeps: []string{
+ "${aconfig}",
+ },
+ Restat: true,
+ }, "release_version", "namespace", "values")
+
+ // For device_config_definitions: Generate java file
+ srcJarRule = pctx.AndroidStaticRule("aconfig_srcjar",
+ blueprint.RuleParams{
+ Command: `rm -rf ${out}.tmp` +
+ ` && mkdir -p ${out}.tmp` +
+ ` && ${aconfig} create-java-lib` +
+ ` --cache ${in}` +
+ ` --out ${out}.tmp` +
+ ` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
+ ` && rm -rf ${out}.tmp`,
+ CommandDeps: []string{
+ "$aconfig",
+ "$soong_zip",
+ },
+ Restat: true,
+ })
+)
+
+func init() {
+ registerBuildComponents(android.InitRegistrationContext)
+}
+
+func registerBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("device_config_definitions", DefinitionsFactory)
+ ctx.RegisterModuleType("device_config_values", ValuesFactory)
+ ctx.RegisterModuleType("device_config_value_set", ValueSetFactory)
+ pctx.HostBinToolVariable("aconfig", "aconfig")
+ pctx.HostBinToolVariable("soong_zip", "soong_zip")
+}
diff --git a/device_config/testing.go b/device_config/testing.go
new file mode 100644
index 0000000..f054476
--- /dev/null
+++ b/device_config/testing.go
@@ -0,0 +1,19 @@
+// Copyright (C) 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 device_config
+
+import "android/soong/android"
+
+var PrepareForTestWithSyspropBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents)
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 6817dce..3e1bbde 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -652,9 +652,7 @@
prop := snapshot.SnapshotJsonFlags{}
propOut := snapshotLibOut + ".json"
prop.InitBaseSnapshotProps(m)
- if m.subdirProperties.Relative_install_path != nil {
- prop.RelativeInstallPath = *m.subdirProperties.Relative_install_path
- }
+ prop.RelativeInstallPath = m.SubDir()
if m.properties.Filename != nil {
prop.Filename = *m.properties.Filename
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 79d2412..2a1b404 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -61,6 +61,7 @@
type FileToZip struct {
SourceFilePath android.Path
DestinationPathPrefix string
+ DestinationPath string
}
type ArchOs struct {
@@ -339,7 +340,7 @@
// List of modules for monitoring coverage drops in directories (e.g. "libicu")
Target_modules []string `json:"target_modules,omitempty"`
// Specifies a bug assignee to replace default ISE assignment
- Assignee string `json:"assignee,omitempty"`
+ Triage_assignee string `json:"triage_assignee,omitempty"`
}
type FuzzFrameworks struct {
@@ -443,7 +444,7 @@
FlagWithOutput("-o ", corpusZip)
rspFile := corpusZip.ReplaceExtension(ctx, "rsp")
command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.Corpus)
- files = append(files, FileToZip{corpusZip, ""})
+ files = append(files, FileToZip{SourceFilePath: corpusZip})
}
// Package the data into a zipfile.
@@ -456,17 +457,17 @@
command.FlagWithArg("-C ", intermediateDir)
command.FlagWithInput("-f ", f)
}
- files = append(files, FileToZip{dataZip, ""})
+ files = append(files, FileToZip{SourceFilePath: dataZip})
}
// The dictionary.
if fuzzModule.Dictionary != nil {
- files = append(files, FileToZip{fuzzModule.Dictionary, ""})
+ files = append(files, FileToZip{SourceFilePath: fuzzModule.Dictionary})
}
// Additional fuzz config.
if fuzzModule.Config != nil && IsValidConfig(fuzzModule, module.Name()) {
- files = append(files, FileToZip{fuzzModule.Config, ""})
+ files = append(files, FileToZip{SourceFilePath: fuzzModule.Config})
}
return files
@@ -485,6 +486,9 @@
} else {
command.Flag("-P ''")
}
+ if file.DestinationPath != "" {
+ command.FlagWithArg("-e ", file.DestinationPath)
+ }
command.FlagWithInput("-f ", file.SourceFilePath)
}
@@ -502,7 +506,7 @@
}
s.FuzzTargets[module.Name()] = true
- archDirs[archOs] = append(archDirs[archOs], FileToZip{fuzzZip, ""})
+ archDirs[archOs] = append(archDirs[archOs], FileToZip{SourceFilePath: fuzzZip})
return archDirs[archOs], true
}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index f5da50e..00adb70 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -940,7 +940,7 @@
}
}
- tags := android.ApexAvailableTags(m)
+ tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
if ctx.ModuleType() == "gensrcs" {
// The Output_extension prop is not in an immediately accessible field
diff --git a/go.mod b/go.mod
index a5d9dd5..4a511c5 100644
--- a/go.mod
+++ b/go.mod
@@ -6,4 +6,5 @@
github.com/google/blueprint v0.0.0
google.golang.org/protobuf v0.0.0
prebuilts/bazel/common/proto/analysis_v2 v0.0.0
+ go.starlark.net v0.0.0
)
diff --git a/go.work b/go.work
index 737a9df..67f6549 100644
--- a/go.work
+++ b/go.work
@@ -4,6 +4,7 @@
.
../../external/go-cmp
../../external/golang-protobuf
+ ../../external/starlark-go
../../prebuilts/bazel/common/proto/analysis_v2
../../prebuilts/bazel/common/proto/build
../blueprint
@@ -16,4 +17,5 @@
google.golang.org/protobuf v0.0.0 => ../../external/golang-protobuf
prebuilts/bazel/common/proto/analysis_v2 v0.0.0 => ../../prebuilts/bazel/common/proto/analysis_v2
prebuilts/bazel/common/proto/build v0.0.0 => ../../prebuilts/bazel/common/proto/build
+ go.starlark.net v0.0.0 => ../../external/starlark-go
)
diff --git a/java/aar.go b/java/aar.go
index f1b137d..29e86e6 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -1056,7 +1056,7 @@
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: "aar_import",
- Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
+ Bzl_load_location: "//build/bazel/rules/android:aar_import.bzl",
},
android.CommonAttributes{Name: name},
&bazelAndroidLibraryImport{
@@ -1086,7 +1086,7 @@
func AndroidLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
return bazel.BazelTargetModuleProperties{
Rule_class: "android_library",
- Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
+ Bzl_load_location: "//build/bazel/rules/android:android_library.bzl",
}
}
diff --git a/java/app.go b/java/app.go
index 03e2330..e095092 100755
--- a/java/app.go
+++ b/java/app.go
@@ -33,8 +33,17 @@
func init() {
RegisterAppBuildComponents(android.InitRegistrationContext)
+ pctx.HostBinToolVariable("ModifyAllowlistCmd", "modify_permissions_allowlist")
}
+var (
+ modifyAllowlist = pctx.AndroidStaticRule("modifyAllowlist",
+ blueprint.RuleParams{
+ Command: "${ModifyAllowlistCmd} $in $packageName $out",
+ CommandDeps: []string{"${ModifyAllowlistCmd}"},
+ }, "packageName")
+)
+
func RegisterAppBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("android_app", AndroidAppFactory)
ctx.RegisterModuleType("android_test", AndroidTestFactory)
@@ -115,6 +124,9 @@
// Prefer using other specific properties if build behaviour must be changed; avoid using this
// flag for anything but neverallow rules (unless the behaviour change is invisible to owners).
Updatable *bool
+
+ // Specifies the file that contains the allowlist for this app.
+ Privapp_allowlist *string `android:"path"`
}
// android_app properties that can be overridden by override_android_app
@@ -179,6 +191,8 @@
android.ApexBundleDepsInfo
javaApiUsedByOutputFile android.ModuleOutPath
+
+ privAppAllowlist android.OptionalPath
}
func (a *AndroidApp) IsInstallable() bool {
@@ -205,6 +219,10 @@
return a.jniCoverageOutputs
}
+func (a *AndroidApp) PrivAppAllowlist() android.OptionalPath {
+ return a.privAppAllowlist
+}
+
var _ AndroidLibraryDependency = (*AndroidApp)(nil)
type Certificate struct {
@@ -269,6 +287,10 @@
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
+ if a.appProperties.Privapp_allowlist != nil && !Bool(a.appProperties.Privileged) {
+ ctx.PropertyErrorf("privapp_allowlist", "privileged must be set in order to use privapp_allowlist")
+ }
+
for _, cert := range a.appProperties.Additional_certificates {
cert = android.SrcIsModule(cert)
if cert != "" {
@@ -563,19 +585,6 @@
certificates = append([]Certificate{mainCert}, certificates...)
}
- if !m.Platform() {
- certPath := certificates[0].Pem.String()
- systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
- if strings.HasPrefix(certPath, systemCertPath) {
- enforceSystemCert := ctx.Config().EnforceSystemCertificate()
- allowed := ctx.Config().EnforceSystemCertificateAllowList()
-
- if enforceSystemCert && !inList(m.Name(), allowed) {
- ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
- }
- }
- }
-
if len(certificates) > 0 {
mainCertificate = certificates[0]
} else {
@@ -591,6 +600,20 @@
}
}
+ if !m.Platform() {
+ certPath := mainCertificate.Pem.String()
+ systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
+ if strings.HasPrefix(certPath, systemCertPath) {
+ enforceSystemCert := ctx.Config().EnforceSystemCertificate()
+ allowed := ctx.Config().EnforceSystemCertificateAllowList()
+
+ if enforceSystemCert && !inList(m.Name(), allowed) {
+ ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
+ }
+ }
+ }
+
+
return mainCertificate, certificates
}
@@ -598,6 +621,27 @@
return a.installApkName
}
+func (a *AndroidApp) createPrivappAllowlist(ctx android.ModuleContext) *android.OutputPath {
+ if a.appProperties.Privapp_allowlist == nil {
+ return nil
+ }
+ if a.overridableAppProperties.Package_name == nil {
+ ctx.PropertyErrorf("privapp_allowlist", "package_name must be set to use privapp_allowlist")
+ }
+ packageName := *a.overridableAppProperties.Package_name
+ fileName := "privapp_allowlist_" + packageName + ".xml"
+ outPath := android.PathForModuleOut(ctx, fileName).OutputPath
+ ctx.Build(pctx, android.BuildParams{
+ Rule: modifyAllowlist,
+ Input: android.PathForModuleSrc(ctx, *a.appProperties.Privapp_allowlist),
+ Output: outPath,
+ Args: map[string]string{
+ "packageName": packageName,
+ },
+ })
+ return &outPath
+}
+
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
var apkDeps android.Paths
@@ -733,18 +777,27 @@
BuildBundleModule(ctx, bundleFile, a.exportPackage, jniJarFile, dexJarFile)
a.bundleFile = bundleFile
+ allowlist := a.createPrivappAllowlist(ctx)
+ if allowlist != nil {
+ a.privAppAllowlist = android.OptionalPathForPath(allowlist)
+ }
+
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
// Install the app package.
- if (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() &&
- !a.appProperties.PreventInstall {
-
+ shouldInstallAppPackage := (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() && !a.appProperties.PreventInstall
+ if shouldInstallAppPackage {
var extraInstalledPaths android.Paths
for _, extra := range a.extraOutputFiles {
installed := ctx.InstallFile(a.installDir, extra.Base(), extra)
extraInstalledPaths = append(extraInstalledPaths, installed)
}
ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
+
+ if a.privAppAllowlist.Valid() {
+ installPath := android.PathForModuleInstall(ctx, "etc", "permissions")
+ ctx.InstallFile(installPath, a.privAppAllowlist.Path().Base(), a.privAppAllowlist.Path())
+ }
}
a.buildAppDependencyInfo(ctx)
@@ -1461,10 +1514,8 @@
// verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the build
// system and returns the path to a copy of the APK.
-func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
+func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) {
u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file
- outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
- return outputFile
}
// For Bazel / bp2build
@@ -1489,7 +1540,7 @@
props := bazel.BazelTargetModuleProperties{
Rule_class: "android_app_certificate",
- Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
+ Bzl_load_location: "//build/bazel/rules/android:android_app_certificate.bzl",
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
@@ -1542,7 +1593,7 @@
props := bazel.BazelTargetModuleProperties{
Rule_class: "android_binary",
- Bzl_load_location: "//build/bazel/rules/android:rules.bzl",
+ Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
}
if !bp2BuildInfo.hasKotlin {
@@ -1572,7 +1623,7 @@
ctx.CreateBazelTargetModule(
props,
- android.CommonAttributes{Name: a.Name()},
+ android.CommonAttributes{Name: a.Name(), SkipData: proptools.BoolPtr(true)},
appAttrs,
)
diff --git a/java/app_import.go b/java/app_import.go
index 85b35eb..9c01960 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -49,6 +49,17 @@
CommandDeps: []string{"${config.Zip2ZipCmd}"},
Description: "Uncompress dex files",
})
+
+ checkJniAndDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-and-dex-libs-are-uncompressed", blueprint.RuleParams{
+ // grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
+ Command: "if (zipinfo $in 'lib/*.so' '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
+ "echo $in: Contains compressed JNI libraries and/or dex files >&2;" +
+ "exit 1; " +
+ "else " +
+ "touch $out; " +
+ "fi",
+ Description: "Check for compressed JNI libs or dex files",
+ })
)
func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
@@ -73,8 +84,6 @@
usesLibrary usesLibrary
- preprocessed bool
-
installPath android.InstallPath
hideApexVariantFromMake bool
@@ -128,6 +137,13 @@
// Optional. Install to a subdirectory of the default install path for the module
Relative_install_path *string
+
+ // Whether the prebuilt apk can be installed without additional processing. Default is false.
+ Preprocessed *bool
+
+ // Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed
+ // JNI libs and dex files. Default is false
+ Skip_preprocessed_apk_checks *bool
}
func (a *AndroidAppImport) IsInstallable() bool {
@@ -201,7 +217,7 @@
ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
// with them may invalidate pre-existing signature data.
- if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || a.preprocessed) {
+ if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Output: outputPath,
@@ -219,7 +235,7 @@
// Returns whether this module should have the dex file stored uncompressed in the APK.
func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
- if ctx.Config().UnbundledBuild() || a.preprocessed {
+ if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
return false
}
@@ -297,7 +313,7 @@
a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
if a.usesLibrary.enforceUsesLibraries() {
- srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+ a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
}
a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
@@ -317,8 +333,14 @@
// Sign or align the package if package has not been preprocessed
- if a.preprocessed {
- a.outputFile = srcApk
+ if proptools.Bool(a.properties.Preprocessed) {
+ output := srcApk
+ if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
+ writableOutput := android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
+ a.validatePreprocessedApk(ctx, srcApk, writableOutput)
+ output = writableOutput
+ }
+ a.outputFile = output
a.certificate = PresignedCertificate
} else if !Bool(a.properties.Presigned) {
// If the certificate property is empty at this point, default_dev_cert must be set to true.
@@ -352,6 +374,30 @@
// TODO: androidmk converter jni libs
}
+func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) {
+ alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: checkZipAlignment,
+ Input: srcApk,
+ Output: alignmentStamp,
+ })
+ compressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "compression.stamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: checkJniAndDexLibsAreUncompressedRule,
+ Input: srcApk,
+ Output: compressionStamp,
+ })
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: srcApk,
+ Output: dstApk,
+ Validations: []android.Path{
+ alignmentStamp,
+ compressionStamp,
+ },
+ })
+}
+
func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
return &a.prebuilt
}
@@ -376,6 +422,10 @@
return a.provenanceMetaDataFile
}
+func (a *AndroidAppImport) PrivAppAllowlist() android.OptionalPath {
+ return android.OptionalPath{}
+}
+
var dpiVariantGroupType reflect.Type
var archVariantGroupType reflect.Type
var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"}
@@ -487,11 +537,6 @@
return module
}
-type androidTestImportProperties struct {
- // Whether the prebuilt apk can be installed without additional processing. Default is false.
- Preprocessed *bool
-}
-
type AndroidTestImport struct {
AndroidAppImport
@@ -508,14 +553,10 @@
Per_testcase_directory *bool
}
- testImportProperties androidTestImportProperties
-
data android.Paths
}
func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- a.preprocessed = Bool(a.testImportProperties.Preprocessed)
-
a.generateAndroidBuildActions(ctx)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
@@ -532,7 +573,6 @@
module.AddProperties(&module.properties)
module.AddProperties(&module.dexpreoptProperties)
module.AddProperties(&module.testProperties)
- module.AddProperties(&module.testImportProperties)
module.populateAllVariantStructs()
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
module.processVariants(ctx)
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 8093024..bb8fab9 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -657,6 +657,29 @@
}
}
+func TestAndroidAppImport_Preprocessed(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ preprocessed: true,
+ }
+ `)
+
+ apkName := "foo.apk"
+ variant := ctx.ModuleForTests("foo", "android_common")
+ outputBuildParams := variant.Output("validated-prebuilt/" + apkName).BuildParams
+ if outputBuildParams.Rule.String() != android.Cp.String() {
+ t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+ }
+
+ // Make sure compression and aligning were validated.
+ if len(outputBuildParams.Validations) != 2 {
+ t.Errorf("Expected compression/alignment validation rules, found %d validations", len(outputBuildParams.Validations))
+ }
+}
+
func TestAndroidTestImport_UncompressDex(t *testing.T) {
testCases := []struct {
name string
diff --git a/java/app_test.go b/java/app_test.go
index 7e97b0f..c485478 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -443,9 +443,9 @@
inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits
var crtbeginFound, crtendFound bool
expectedCrtBegin := ctx.ModuleForTests("crtbegin_so",
- "android_arm64_armv8-a_sdk_29").Rule("partialLd").Output
+ "android_arm64_armv8-a_sdk_29").Rule("noAddrSig").Output
expectedCrtEnd := ctx.ModuleForTests("crtend_so",
- "android_arm64_armv8-a_sdk_29").Rule("partialLd").Output
+ "android_arm64_armv8-a_sdk_29").Rule("noAddrSig").Output
implicits := []string{}
for _, input := range inputs {
implicits = append(implicits, input.String())
@@ -3382,6 +3382,14 @@
srcs: ["a.java"],
certificate: ":missing_certificate",
sdk_version: "current",
+ }
+
+ android_app {
+ name: "bar",
+ srcs: ["a.java"],
+ certificate: ":missing_certificate",
+ product_specific: true,
+ sdk_version: "current",
}`)
foo := result.ModuleForTests("foo", "android_common")
@@ -3539,3 +3547,51 @@
android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected)
}
}
+
+func TestPrivappAllowlist(t *testing.T) {
+ testJavaError(t, "privileged must be set in order to use privapp_allowlist", `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ privapp_allowlist: "perms.xml",
+ }
+ `)
+
+ result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(
+ t,
+ `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ privapp_allowlist: "perms.xml",
+ privileged: true,
+ package_name: "com.android.foo",
+ sdk_version: "current",
+ }
+ override_android_app {
+ name: "bar",
+ base: "foo",
+ package_name: "com.google.android.foo",
+ }
+ `,
+ )
+ app := result.ModuleForTests("foo", "android_common")
+ overrideApp := result.ModuleForTests("foo", "android_common_bar")
+
+ // verify that privapp allowlist is created
+ app.Output("out/soong/.intermediates/foo/android_common/privapp_allowlist_com.android.foo.xml")
+ overrideApp.Output("out/soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml")
+ expectedAllowlist := "perms.xml"
+ actualAllowlist := app.Rule("modifyAllowlist").Input.String()
+ if expectedAllowlist != actualAllowlist {
+ t.Errorf("expected allowlist to be %q; got %q", expectedAllowlist, actualAllowlist)
+ }
+ overrideActualAllowlist := overrideApp.Rule("modifyAllowlist").Input.String()
+ if expectedAllowlist != overrideActualAllowlist {
+ t.Errorf("expected override allowlist to be %q; got %q", expectedAllowlist, overrideActualAllowlist)
+ }
+
+ // verify that permissions are copied to device
+ app.Output("out/soong/target/product/test_device/system/etc/permissions/privapp_allowlist_com.android.foo.xml")
+ overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/privapp_allowlist_com.google.android.foo.xml")
+}
diff --git a/java/base.go b/java/base.go
index 9911323..374138c 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1923,9 +1923,12 @@
func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
switch name {
- case android.SdkCore.JavaLibraryName(ctx.Config()), "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
+ case android.SdkCore.JavaLibraryName(ctx.Config()),
+ android.JavaApiLibraryName(ctx.Config(), "legacy.core.platform.api.stubs"),
+ android.JavaApiLibraryName(ctx.Config(), "stable.core.platform.api.stubs"),
"stub-annotations", "private-stub-annotations-jar",
- "core-lambda-stubs", "core-generated-annotation-stubs":
+ android.JavaApiLibraryName(ctx.Config(), "core-lambda-stubs"),
+ "core-generated-annotation-stubs":
return javaCore, true
case android.SdkPublic.JavaLibraryName(ctx.Config()):
return javaSdk, true
diff --git a/java/builder.go b/java/builder.go
index 4626267..0c57738 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -246,6 +246,19 @@
CommandDeps: []string{"${config.ZipAlign}"},
},
)
+
+ checkZipAlignment = pctx.AndroidStaticRule("checkzipalign",
+ blueprint.RuleParams{
+ Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
+ "echo $in: Improper package alignment >&2; " +
+ "exit 1; " +
+ "else " +
+ "touch $out; " +
+ "fi",
+ CommandDeps: []string{"${config.ZipAlign}"},
+ Description: "Check zip alignment",
+ },
+ )
)
func init() {
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 273aca0..d383d98 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -28,8 +28,11 @@
ctx.Strict("FRAMEWORK_LIBRARIES", strings.Join(FrameworkLibraries, " "))
// These are used by make when LOCAL_PRIVATE_PLATFORM_APIS is set (equivalent to platform_apis in blueprint):
- ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES", strings.Join(LegacyCorePlatformBootclasspathLibraries, " "))
- ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES", LegacyCorePlatformSystemModules)
+ ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES",
+ strings.Join(android.JavaApiLibraryNames(ctx.Config(), LegacyCorePlatformBootclasspathLibraries), " "))
+ ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES",
+ android.JavaApiLibraryName(ctx.Config(), LegacyCorePlatformSystemModules),
+ )
ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
diff --git a/java/dex.go b/java/dex.go
index 4d6aa34..7e7da00 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -140,7 +140,7 @@
`$r8Template${config.R8Cmd} ${config.R8Flags} -injars $tmpJar --output $outDir ` +
`--no-data-resources ` +
`-printmapping ${outDict} ` +
- `--pg-conf-output ${outConfig} ` +
+ `-printconfiguration ${outConfig} ` +
`-printusage ${outUsage} ` +
`--deps-file ${out}.d ` +
`$r8Flags && ` +
@@ -161,7 +161,7 @@
"$r8Template": &remoteexec.REParams{
Labels: map[string]string{"type": "compile", "compiler": "r8"},
Inputs: []string{"$implicits", "${config.R8Jar}"},
- OutputFiles: []string{"${outUsage}"},
+ OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}"},
ExecStrategy: "${config.RER8ExecStrategy}",
ToolchainInputs: []string{"${config.JavaCmd}"},
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
@@ -399,13 +399,16 @@
args["implicits"] = strings.Join(r8Deps.Strings(), ",")
}
ctx.Build(pctx, android.BuildParams{
- Rule: rule,
- Description: "r8",
- Output: javalibJar,
- ImplicitOutputs: android.WritablePaths{proguardDictionary, proguardUsageZip},
- Input: dexParams.classesJar,
- Implicits: r8Deps,
- Args: args,
+ Rule: rule,
+ Description: "r8",
+ Output: javalibJar,
+ ImplicitOutputs: android.WritablePaths{
+ proguardDictionary,
+ proguardUsageZip,
+ proguardConfiguration},
+ Input: dexParams.classesJar,
+ Implicits: r8Deps,
+ Args: args,
})
} else {
d8Flags, d8Deps := d8Flags(dexParams.flags)
diff --git a/java/fuzz.go b/java/fuzz.go
index 2b9e22b..4aa6dbf 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -175,11 +175,11 @@
files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder)
// Add .jar
- files = append(files, fuzz.FileToZip{javaFuzzModule.implementationJarFile, ""})
+ files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.implementationJarFile})
// Add jni .so files
for _, fPath := range javaFuzzModule.jniFilePaths {
- files = append(files, fuzz.FileToZip{fPath, ""})
+ files = append(files, fuzz.FileToZip{SourceFilePath: fPath})
}
archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaFuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index c6176e6..96e084a 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -241,7 +241,7 @@
testStubModules = append(testStubModules, android.SdkTest.JavaLibraryName(config))
}
// We do not have prebuilts of the core platform api yet
- corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
+ corePlatformStubModules = append(corePlatformStubModules, android.JavaApiLibraryName(config, "legacy.core.platform.api.stubs"))
// Allow products to define their own stubs for custom product jars that apps can use.
publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
diff --git a/java/java.go b/java/java.go
index 683e546..65bfce0 100644
--- a/java/java.go
+++ b/java/java.go
@@ -456,7 +456,9 @@
ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...)
if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
- ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
+ ctx.AddVariationDependencies(nil, proguardRaiseTag,
+ android.JavaApiLibraryNames(ctx.Config(), config.LegacyCorePlatformBootclasspathLibraries)...,
+ )
}
if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
@@ -813,7 +815,10 @@
// If the min_sdk_version was set then add the canonical representation of the API level to the
// snapshot.
if j.deviceProperties.Min_sdk_version != nil {
- canonical := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String())
+ canonical, err := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String())
+ if err != nil {
+ ctx.ModuleErrorf("%s", err)
+ }
p.MinSdkVersion = proptools.StringPtr(canonical)
}
@@ -2704,8 +2709,13 @@
var resources bazel.LabelList
var resourceStripPrefix *string
+ if m.properties.Java_resources != nil && len(m.properties.Java_resource_dirs) > 0 {
+ ctx.ModuleErrorf("bp2build doesn't support both java_resources and java_resource_dirs being set on the same module.")
+ }
+
if m.properties.Java_resources != nil {
resources.Append(android.BazelLabelForModuleSrc(ctx, m.properties.Java_resources))
+ resourceStripPrefix = proptools.StringPtr(ctx.ModuleDir())
}
//TODO(b/179889880) handle case where glob includes files outside package
@@ -2836,7 +2846,7 @@
return android.IsConvertedToAidlLibrary(ctx, src.OriginalModuleName)
})
- apexAvailableTags := android.ApexAvailableTags(ctx.Module())
+ apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
if !aidlSrcs.IsEmpty() {
aidlLibName := m.Name() + "_aidl_library"
@@ -2962,14 +2972,14 @@
func ktJvmLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
return bazel.BazelTargetModuleProperties{
Rule_class: "kt_jvm_library",
- Bzl_load_location: "//build/bazel/rules/kotlin:rules.bzl",
+ Bzl_load_location: "//build/bazel/rules/kotlin:kt_jvm_library.bzl",
}
}
func javaLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
return bazel.BazelTargetModuleProperties{
Rule_class: "java_library",
- Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
+ Bzl_load_location: "//build/bazel/rules/java:library.bzl",
}
}
@@ -3078,7 +3088,7 @@
props := bazel.BazelTargetModuleProperties{
Rule_class: "java_binary",
- Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
+ Bzl_load_location: "@rules_java//java:defs.bzl",
}
binAttrs := &javaBinaryHostAttributes{
Runtime_deps: runtimeDeps,
@@ -3134,7 +3144,7 @@
}
props := bazel.BazelTargetModuleProperties{
Rule_class: "java_import",
- Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
+ Bzl_load_location: "//build/bazel/rules/java:import.bzl",
}
name := android.RemoveOptionalPrebuiltPrefix(i.Name())
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 6cb549e..04c6d05 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -93,16 +93,16 @@
func corePlatformSystemModules(ctx android.EarlyModuleContext) string {
if useLegacyCorePlatformApi(ctx, ctx.ModuleName()) {
- return config.LegacyCorePlatformSystemModules
+ return android.JavaApiLibraryName(ctx.Config(), config.LegacyCorePlatformSystemModules)
} else {
- return config.StableCorePlatformSystemModules
+ return android.JavaApiLibraryName(ctx.Config(), config.StableCorePlatformSystemModules)
}
}
func corePlatformBootclasspathLibraries(ctx android.EarlyModuleContext) []string {
if useLegacyCorePlatformApi(ctx, ctx.ModuleName()) {
- return config.LegacyCorePlatformBootclasspathLibraries
+ return android.JavaApiLibraryNames(ctx.Config(), config.LegacyCorePlatformBootclasspathLibraries)
} else {
- return config.StableCorePlatformBootclasspathLibraries
+ return android.JavaApiLibraryNames(ctx.Config(), config.StableCorePlatformBootclasspathLibraries)
}
}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 206d995..044802e 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -104,20 +104,51 @@
return fmt.Sprintf("%s_%s_%s_%s", mctx.ModuleName(), scope, version, module)
}
+func hasBazelPrebuilt(module string) bool {
+ return module == "android" || module == "core-for-system-modules"
+}
+
+func bazelPrebuiltApiModuleName(module, scope, version string) string {
+ bazelModule := module
+ switch module {
+ case "android":
+ bazelModule = "android_jar"
+ case "core-for-system-modules":
+ bazelModule = "core_jar"
+ }
+ bazelVersion := version
+ if version == "current" {
+ bazelVersion = strconv.Itoa(android.FutureApiLevelInt)
+ }
+ bazelScope := scope
+ switch scope {
+ case "module-lib":
+ bazelScope = "module"
+ case "system-server":
+ bazelScope = "system_server"
+ }
+ return fmt.Sprintf("//prebuilts/sdk:%s_%s_%s", bazelScope, bazelVersion, bazelModule)
+}
+
func createImport(mctx android.LoadHookContext, module, scope, version, path, sdkVersion string, compileDex bool) {
props := struct {
- Name *string
- Jars []string
- Sdk_version *string
- Installable *bool
- Compile_dex *bool
- }{}
- props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version))
- props.Jars = append(props.Jars, path)
- props.Sdk_version = proptools.StringPtr(sdkVersion)
- props.Installable = proptools.BoolPtr(false)
- props.Compile_dex = proptools.BoolPtr(compileDex)
-
+ Name *string
+ Jars []string
+ Sdk_version *string
+ Installable *bool
+ Compile_dex *bool
+ Bazel_module android.BazelModuleProperties
+ }{
+ Name: proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version)),
+ Jars: []string{path},
+ Sdk_version: proptools.StringPtr(sdkVersion),
+ Installable: proptools.BoolPtr(false),
+ Compile_dex: proptools.BoolPtr(compileDex),
+ }
+ if hasBazelPrebuilt(module) {
+ props.Bazel_module = android.BazelModuleProperties{
+ Label: proptools.StringPtr(bazelPrebuiltApiModuleName(module, scope, version))}
+ }
mctx.CreateModule(ImportFactory, &props)
}
@@ -135,6 +166,19 @@
mctx.CreateModule(genrule.GenRuleFactory, &genruleProps)
}
+func createLatestApiModuleExtensionVersionFile(mctx android.LoadHookContext, name string, version string) {
+ genruleProps := struct {
+ Name *string
+ Srcs []string
+ Out []string
+ Cmd *string
+ }{}
+ genruleProps.Name = proptools.StringPtr(name)
+ genruleProps.Out = []string{name}
+ genruleProps.Cmd = proptools.StringPtr("echo " + version + " > $(out)")
+ mctx.CreateModule(genrule.GenRuleFactory, &genruleProps)
+}
+
func createEmptyFile(mctx android.LoadHookContext, name string) {
props := struct {
Name *string
@@ -233,9 +277,10 @@
type latestApiInfo struct {
module, scope, path string
version int
+ isExtensionApiFile bool
}
- getLatest := func(files []string) map[string]latestApiInfo {
+ getLatest := func(files []string, isExtensionApiFile bool) map[string]latestApiInfo {
m := make(map[string]latestApiInfo)
for _, f := range files {
module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
@@ -245,16 +290,16 @@
key := module + "." + scope
info, exists := m[key]
if !exists || version > info.version {
- m[key] = latestApiInfo{module, scope, f, version}
+ m[key] = latestApiInfo{module, scope, f, version, isExtensionApiFile}
}
}
return m
}
- latest := getLatest(apiLevelFiles)
+ latest := getLatest(apiLevelFiles, false)
if p.properties.Extensions_dir != nil {
extensionApiFiles := globExtensionDirs(mctx, p, "api/*.txt")
- for k, v := range getLatest(extensionApiFiles) {
+ for k, v := range getLatest(extensionApiFiles, true) {
if _, exists := latest[k]; !exists {
mctx.ModuleErrorf("Module %v finalized for extension %d but never during an API level; likely error", v.module, v.version)
}
@@ -267,6 +312,12 @@
for _, k := range android.SortedKeys(latest) {
info := latest[k]
name := PrebuiltApiModuleName(info.module, info.scope, "latest")
+ latestExtensionVersionModuleName := PrebuiltApiModuleName(info.module, info.scope, "latest.extension_version")
+ if info.isExtensionApiFile {
+ createLatestApiModuleExtensionVersionFile(mctx, latestExtensionVersionModuleName, strconv.Itoa(info.version))
+ } else {
+ createLatestApiModuleExtensionVersionFile(mctx, latestExtensionVersionModuleName, "-1")
+ }
createApiModule(mctx, name, info.path)
}
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 77394d9..8225df6 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -163,6 +163,21 @@
var identifierFullMatchRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
+func RelativeToCwd(path string) (string, error) {
+ cwd, err := os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ path, err = filepath.Rel(cwd, path)
+ if err != nil {
+ return "", err
+ }
+ if strings.HasPrefix(path, "../") {
+ return "", fmt.Errorf("Could not make path relative to current working directory: " + path)
+ }
+ return path, nil
+}
+
// Conversion request parameters
type Request struct {
MkFile string // file to convert
@@ -320,6 +335,14 @@
loadedSubConfigs := make(map[string]string)
for _, mi := range gctx.starScript.inherited {
uri := mi.path
+ if strings.HasPrefix(uri, "/") && !strings.HasPrefix(uri, "//") {
+ var err error
+ uri, err = RelativeToCwd(uri)
+ if err != nil {
+ panic(err)
+ }
+ uri = "//" + uri
+ }
if m, ok := loadedSubConfigs[uri]; ok {
// No need to emit load statement, but fix module name.
mi.moduleLocalName = m
diff --git a/mk2rbc/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc/mk2rbc.go
index cc83430..08c363f 100644
--- a/mk2rbc/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc/mk2rbc.go
@@ -187,7 +187,7 @@
quit(fmt.Errorf("the product launcher input variables file failed to convert"))
}
- err := writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(files[0]), outputFilePath(*inputVariables),
+ err := writeGenerated(*launcher, mk2rbc.Launcher(outputModulePath(files[0]), outputModulePath(*inputVariables),
mk2rbc.MakePath2ModuleName(files[0])))
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
@@ -205,7 +205,7 @@
quit(fmt.Errorf("the board launcher input variables file failed to convert"))
}
err := writeGenerated(*boardlauncher, mk2rbc.BoardLauncher(
- outputFilePath(files[0]), outputFilePath(*inputVariables)))
+ outputModulePath(files[0]), outputModulePath(*inputVariables)))
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
ok = false
@@ -402,6 +402,15 @@
return path
}
+func outputModulePath(mkFile string) string {
+ path := outputFilePath(mkFile)
+ path, err := mk2rbc.RelativeToCwd(path)
+ if err != nil {
+ panic(err)
+ }
+ return "//" + path
+}
+
func writeGenerated(path string, contents string) error {
if err := os.MkdirAll(filepath.Dir(path), os.ModeDir|os.ModePerm); err != nil {
return err
diff --git a/mk2rbc/soong_variables_test.go b/mk2rbc/soong_variables_test.go
index c883882..58e98f6 100644
--- a/mk2rbc/soong_variables_test.go
+++ b/mk2rbc/soong_variables_test.go
@@ -42,8 +42,8 @@
{"BUILD_ID", VarClassSoong, starlarkTypeString},
{"PLATFORM_SDK_VERSION", VarClassSoong, starlarkTypeInt},
{"DEVICE_PACKAGE_OVERLAYS", VarClassSoong, starlarkTypeList},
- {"ENABLE_CFI", VarClassSoong, starlarkTypeBool},
- {"ENABLE_PREOPT", VarClassSoong, starlarkTypeBool},
+ {"ENABLE_CFI", VarClassSoong, starlarkTypeString},
+ {"ENABLE_PREOPT", VarClassSoong, starlarkTypeString},
}}
if !reflect.DeepEqual(expected, actual) {
t.Errorf("\nExpected: %v\n Actual: %v", expected, actual)
diff --git a/python/python.go b/python/python.go
index 1a12973..8fde638 100644
--- a/python/python.go
+++ b/python/python.go
@@ -265,7 +265,6 @@
}
if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
if !mctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
- mctx.ModuleName() != "par_test" &&
mctx.ModuleName() != "py2-cmd" &&
mctx.ModuleName() != "py2-stdlib" {
mctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration")
diff --git a/python/tests/Android.bp b/python/tests/Android.bp
index a656859..e5569ba 100644
--- a/python/tests/Android.bp
+++ b/python/tests/Android.bp
@@ -28,29 +28,6 @@
unit_test: false,
},
version: {
- py2: {
- enabled: true,
- embedded_launcher: true,
- },
- py3: {
- enabled: false,
- embedded_launcher: true,
- },
- },
-}
-
-python_test_host {
- name: "par_test3",
- main: "par_test.py",
- srcs: [
- "par_test.py",
- "testpkg/par_test.py",
- ],
- // Is not implemented as a python unittest
- test_options: {
- unit_test: false,
- },
- version: {
py3: {
embedded_launcher: true,
},
diff --git a/python/tests/py-cmd_test.py b/python/tests/py-cmd_test.py
index acda2d7..c7ba0ab 100644
--- a/python/tests/py-cmd_test.py
+++ b/python/tests/py-cmd_test.py
@@ -57,7 +57,7 @@
if sys.version_info[0] == 2:
assert_equal("len(sys.path)", len(sys.path), 4)
- assert_equal("sys.path[0]", sys.path[0], os.path.dirname(__file__))
+ assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__)))
assert_equal("sys.path[1]", sys.path[1], "/extra")
assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, "internal"))
assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, "internal", "stdlib"))
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
index 35941dc..f4abae5 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -24,10 +24,9 @@
fi
if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) ||
- ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 ) ||
( ! -f $ANDROID_HOST_OUT/bin/py2-cmd ) ||
( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then
- echo "Run 'm par_test par_test3 py2-cmd py3-cmd' first"
+ echo "Run 'm par_test py2-cmd py3-cmd' first"
exit 1
fi
@@ -41,12 +40,6 @@
ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test/par_test --arg1 arg2
-PYTHONHOME= PYTHONPATH= $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
-PYTHONHOME=/usr $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
-PYTHONPATH=/usr $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
-
-ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 --arg1 arg2
-
cd $(dirname ${BASH_SOURCE[0]})
PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py
diff --git a/python/tests/testpkg/par_test.py b/python/tests/testpkg/par_test.py
index b513409..e12c527 100644
--- a/python/tests/testpkg/par_test.py
+++ b/python/tests/testpkg/par_test.py
@@ -33,11 +33,7 @@
fileName = fileName[:-1]
assert_equal("__file__", fileName, os.path.join(archive, "testpkg/par_test.py"))
-# Python3 is returning None here for me, and I haven't found any problems caused by this.
-if sys.version_info[0] == 2:
- assert_equal("__package__", __package__, "testpkg")
-else:
- assert_equal("__package__", __package__, None)
+assert_equal("__package__", __package__, "testpkg")
assert_equal("__loader__.archive", __loader__.archive, archive)
assert_equal("__loader__.prefix", __loader__.prefix, "testpkg/")
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 13fa81e..96645b0 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
defaultBindgenFlags = []string{""}
// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
- bindgenClangVersion = "clang-r487747"
+ bindgenClangVersion = "clang-r487747c"
_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
diff --git a/rust/config/global.go b/rust/config/global.go
index 2d1f0c1..748bb3d 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.68.0"
+ RustDefaultVersion = "1.69.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2021"
Stdlibs = []string{
diff --git a/rust/fuzz.go b/rust/fuzz.go
index d7e7ddf..c2b9405 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -31,7 +31,7 @@
*binaryDecorator
fuzzPackagedModule fuzz.FuzzPackagedModule
- sharedLibraries android.Paths
+ sharedLibraries android.RuleBuilderInstalls
installedSharedDeps []string
}
@@ -119,15 +119,17 @@
// Grab the list of required shared libraries.
fuzz.sharedLibraries, _ = cc.CollectAllSharedDependencies(ctx)
- for _, lib := range fuzz.sharedLibraries {
+ for _, ruleBuilderInstall := range fuzz.sharedLibraries {
+ install := ruleBuilderInstall.To
+
fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
cc.SharedLibraryInstallLocation(
- lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
+ install, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
// Also add the dependency on the shared library symbols dir.
if !ctx.Host() {
fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
- cc.SharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String()))
+ cc.SharedLibrarySymbolsInstallLocation(install, installBase, ctx.Arch().ArchType.String()))
}
}
}
diff --git a/rust/protobuf.go b/rust/protobuf.go
index e30f25d..0cf6e8c 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -52,6 +52,10 @@
// List of libraries which export include paths required for this module
Header_libs []string `android:"arch_variant,variant_prepend"`
+
+ // Use protobuf version 3.x. This will be deleted once we migrate all current users
+ // of protobuf off of 2.x.
+ Use_protobuf3 *bool
}
type protobufDecorator struct {
@@ -65,6 +69,10 @@
protoFlags android.ProtoFlags
}
+func (proto *protobufDecorator) useProtobuf3() bool {
+ return Bool(proto.Properties.Use_protobuf3)
+}
+
func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
var protoFlags android.ProtoFlags
var grpcProtoFlags android.ProtoFlags
@@ -73,7 +81,13 @@
outDir := android.PathForModuleOut(ctx)
protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
grpcFiles := android.PathsForModuleSrc(ctx, proto.Properties.Grpc_protos)
+
+ // For now protobuf2 (the deprecated version) remains the default. This will change in the
+ // future as we update the various users.
protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust-deprecated")
+ if proto.useProtobuf3() == true {
+ protoPluginPath = ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
+ }
commonProtoFlags = append(commonProtoFlags, defaultProtobufFlags...)
commonProtoFlags = append(commonProtoFlags, proto.Properties.Proto_flags...)
@@ -206,10 +220,20 @@
func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
- deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
+ useProtobuf3 := proto.useProtobuf3()
+ if useProtobuf3 == true {
+ deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
+ } else {
+ deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
+ }
deps.HeaderLibs = append(deps.SharedLibs, proto.Properties.Header_libs...)
if len(proto.Properties.Grpc_protos) > 0 {
+ if useProtobuf3 == true {
+ ctx.PropertyErrorf("protos", "rust_protobuf with grpc_protos defined must currently use "+
+ "`use_protobuf3: false,` in the Android.bp file. This is temporary until the "+
+ "grpcio crate is updated to use the current version of the protobuf crate.")
+ }
deps.Rustlibs = append(deps.Rustlibs, "libgrpcio", "libfutures")
deps.HeaderLibs = append(deps.HeaderLibs, "libprotobuf-cpp-full")
}
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index 0aa4549..b723f3f 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -69,6 +69,55 @@
}
}
+func TestRustProtobuf3(t *testing.T) {
+ ctx := testRust(t, `
+ rust_protobuf {
+ name: "librust_proto",
+ protos: ["buf.proto", "proto.proto"],
+ crate_name: "rust_proto",
+ source_stem: "buf",
+ use_protobuf3: true,
+ shared_libs: ["libfoo_shared"],
+ static_libs: ["libfoo_static"],
+ }
+ cc_library_shared {
+ name: "libfoo_shared",
+ export_include_dirs: ["shared_include"],
+ }
+ cc_library_static {
+ name: "libfoo_static",
+ export_include_dirs: ["static_include"],
+ }
+ `)
+ // Check that libprotobuf is added as a dependency.
+ librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
+ if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) {
+ t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
+ }
+
+ // Make sure the correct plugin is being used.
+ librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs")
+ cmd := librust_proto_out.RuleParams.Command
+ if w := "protoc-gen-rust"; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+
+ // Check exported include directories
+ if w := "-Ishared_include"; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+ if w := "-Istatic_include"; !strings.Contains(cmd, w) {
+ t.Errorf("expected %q in %q", w, cmd)
+ }
+
+ // Check proto.rs, the second protobuf, is listed as an output
+ librust_proto_outputs := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").AllOutputs()
+ if android.InList("proto.rs", librust_proto_outputs) {
+ t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto.rs' in list, got: %#v ",
+ librust_proto_outputs)
+ }
+}
+
func TestRustGrpc(t *testing.T) {
ctx := testRust(t, `
rust_protobuf {
diff --git a/rust/rust.go b/rust/rust.go
index 7b520cd..dc53cc0 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -649,7 +649,7 @@
panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", mod.BaseModuleName()))
}
-func (mod *Module) FuzzSharedLibraries() android.Paths {
+func (mod *Module) FuzzSharedLibraries() android.RuleBuilderInstalls {
if fuzzer, ok := mod.compiler.(*fuzzDecorator); ok {
return fuzzer.sharedLibraries
}
diff --git a/rust/testing.go b/rust/testing.go
index a33d948..0a6a870 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -127,6 +127,12 @@
min_sdk_version: "29",
}
rust_library {
+ name: "libprotobuf",
+ crate_name: "protobuf",
+ srcs: ["foo.rs"],
+ host_supported: true,
+ }
+ rust_library {
name: "libprotobuf_deprecated",
crate_name: "protobuf",
srcs: ["foo.rs"],
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 9367ff0..97f6ab4 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -237,3 +237,20 @@
name: "jars-to-module-info-java",
src: "jars-to-module-info-java.sh",
}
+
+python_binary_host {
+ name: "modify_permissions_allowlist",
+ main: "modify_permissions_allowlist.py",
+ srcs: [
+ "modify_permissions_allowlist.py",
+ ],
+}
+
+python_test_host {
+ name: "modify_permissions_allowlist_test",
+ main: "modify_permissions_allowlist_test.py",
+ srcs: [
+ "modify_permissions_allowlist_test.py",
+ "modify_permissions_allowlist.py",
+ ],
+}
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index 869fd3f..dad2b47 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -72,6 +72,7 @@
javax\.xml\.validation
javax\.xml\.xpath
jdk\.internal
+jdk\.internal\.access
jdk\.internal\.math
jdk\.internal\.misc
jdk\.internal\.ref
diff --git a/scripts/modify_permissions_allowlist.py b/scripts/modify_permissions_allowlist.py
new file mode 100755
index 0000000..38ec7ec
--- /dev/null
+++ b/scripts/modify_permissions_allowlist.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2022 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.
+#
+"""A tool for modifying privileged permission allowlists."""
+
+from __future__ import print_function
+
+import argparse
+import sys
+from xml.dom import minidom
+
+
+class InvalidRootNodeException(Exception):
+ pass
+
+
+class InvalidNumberOfPrivappPermissionChildren(Exception):
+ pass
+
+
+def modify_allowlist(allowlist_dom, package_name):
+ if allowlist_dom.documentElement.tagName != 'permissions':
+ raise InvalidRootNodeException
+ nodes = allowlist_dom.getElementsByTagName('privapp-permissions')
+ if nodes.length != 1:
+ raise InvalidNumberOfPrivappPermissionChildren
+ privapp_permissions = nodes[0]
+ privapp_permissions.setAttribute('package', package_name)
+
+
+def parse_args():
+ """Parse commandline arguments."""
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('input', help='input allowlist template file')
+ parser.add_argument(
+ 'package_name', help='package name to use in the allowlist'
+ )
+ parser.add_argument('output', help='output allowlist file')
+
+ return parser.parse_args()
+
+
+def main():
+ try:
+ args = parse_args()
+ doc = minidom.parse(args.input)
+ modify_allowlist(doc, args.package_name)
+ with open(args.output, 'w') as output_file:
+ doc.writexml(output_file, encoding='utf-8')
+ except Exception as err:
+ print('error: ' + str(err), file=sys.stderr)
+ sys.exit(-1)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/modify_permissions_allowlist_test.py b/scripts/modify_permissions_allowlist_test.py
new file mode 100755
index 0000000..ee8b12c
--- /dev/null
+++ b/scripts/modify_permissions_allowlist_test.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2022 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.
+#
+"""Unit tests for modify_permissions_allowlist.py."""
+
+from __future__ import print_function
+
+import unittest
+
+from xml.dom import minidom
+
+from modify_permissions_allowlist import InvalidRootNodeException, InvalidNumberOfPrivappPermissionChildren, modify_allowlist
+
+
+class ModifyPermissionsAllowlistTest(unittest.TestCase):
+
+ def test_invalid_root(self):
+ xml_data = '<foo></foo>'
+ xml_dom = minidom.parseString(xml_data)
+ self.assertRaises(InvalidRootNodeException, modify_allowlist, xml_dom, 'x')
+
+ def test_no_packages(self):
+ xml_data = '<permissions></permissions>'
+ xml_dom = minidom.parseString(xml_data)
+ self.assertRaises(
+ InvalidNumberOfPrivappPermissionChildren, modify_allowlist, xml_dom, 'x'
+ )
+
+ def test_multiple_packages(self):
+ xml_data = (
+ '<permissions>'
+ ' <privapp-permissions package="foo.bar"></privapp-permissions>'
+ ' <privapp-permissions package="bar.baz"></privapp-permissions>'
+ '</permissions>'
+ )
+ xml_dom = minidom.parseString(xml_data)
+ self.assertRaises(
+ InvalidNumberOfPrivappPermissionChildren, modify_allowlist, xml_dom, 'x'
+ )
+
+ def test_modify_package_name(self):
+ xml_data = (
+ '<permissions>'
+ ' <privapp-permissions package="foo.bar">'
+ ' <permission name="myperm1"/>'
+ ' </privapp-permissions>'
+ '</permissions>'
+ )
+ xml_dom = minidom.parseString(xml_data)
+ modify_allowlist(xml_dom, 'bar.baz')
+ expected_data = (
+ '<?xml version="1.0" ?>'
+ '<permissions>'
+ ' <privapp-permissions package="bar.baz">'
+ ' <permission name="myperm1"/>'
+ ' </privapp-permissions>'
+ '</permissions>'
+ )
+ self.assertEqual(expected_data, xml_dom.toxml())
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/scripts/rbc-run b/scripts/rbc-run
deleted file mode 100755
index 8d93f0e..0000000
--- a/scripts/rbc-run
+++ /dev/null
@@ -1,18 +0,0 @@
-#! /bin/bash
-# Convert and run one configuration
-# Args: a product/board makefile optionally followed by additional arguments
-# that will be passed to rbcrun.
-[[ $# -gt 1 && -f "$1" && -f "$2" ]] || { echo "Usage: ${0##*/} product.mk input_variables.mk [Additional rbcrun arguments]" >&2; exit 1; }
-set -eu
-
-declare -r output_root="${OUT_DIR:-out}"
-declare -r runner="${output_root}/rbcrun"
-declare -r converter="${output_root}/mk2rbc"
-declare -r launcher="${output_root}/rbc/launcher.rbc"
-declare -r makefile_list="${output_root}/.module_paths/configuration.list"
-declare -r makefile="$1"
-declare -r input_variables="$2"
-shift 2
-"${converter}" -mode=write -r --outdir "${output_root}/rbc" --input_variables "${input_variables}" --launcher="${launcher}" --makefile_list="${makefile_list}" "${makefile}"
-"${runner}" RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ "${launcher}"
-
diff --git a/sdk/update.go b/sdk/update.go
index d98ab68..d3c59b0 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -1963,6 +1963,10 @@
requiredTraits android.SdkMemberTraitSet
}
+func (m *memberContext) ModuleErrorf(fmt string, args ...interface{}) {
+ m.sdkMemberContext.ModuleErrorf(fmt, args...)
+}
+
func (m *memberContext) SdkModuleContext() android.ModuleContext {
return m.sdkMemberContext
}
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index c921ca6..d2eede6 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -474,16 +474,18 @@
}}
}
-func InitShBinaryModule(s *ShBinary) {
+func initShBinaryModule(s *ShBinary, useBazel bool) {
s.AddProperties(&s.properties)
- android.InitBazelModule(s)
+ if useBazel {
+ android.InitBazelModule(s)
+ }
}
// sh_binary is for a shell script or batch file to be installed as an
// executable binary to <partition>/bin.
func ShBinaryFactory() android.Module {
module := &ShBinary{}
- InitShBinaryModule(module)
+ initShBinaryModule(module, true)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
return module
}
@@ -492,7 +494,7 @@
// to $(HOST_OUT)/bin.
func ShBinaryHostFactory() android.Module {
module := &ShBinary{}
- InitShBinaryModule(module)
+ initShBinaryModule(module, true)
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
return module
}
@@ -500,7 +502,7 @@
// sh_test defines a shell script based test module.
func ShTestFactory() android.Module {
module := &ShTest{}
- InitShBinaryModule(&module.ShBinary)
+ initShBinaryModule(&module.ShBinary, false)
module.AddProperties(&module.testProperties)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
@@ -510,7 +512,7 @@
// sh_test_host defines a shell script based test module that runs on a host.
func ShTestHostFactory() android.Module {
module := &ShTest{}
- InitShBinaryModule(&module.ShBinary)
+ initShBinaryModule(&module.ShBinary, false)
module.AddProperties(&module.testProperties)
// Default sh_test_host to unit_tests = true
if module.testProperties.Test_options.Unit_test == nil {
diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go
index a97f71b..4209507 100644
--- a/starlark_fmt/format.go
+++ b/starlark_fmt/format.go
@@ -99,6 +99,16 @@
return PrintDict(valDict, indentLevel)
}
+// PrintStringStringDict returns a Starlark-compatible string formatted as dictionary with
+// string keys and string values.
+func PrintStringStringDict(dict map[string]string, indentLevel int) string {
+ valDict := make(map[string]string, len(dict))
+ for k, v := range dict {
+ valDict[k] = fmt.Sprintf(`"%s"`, v)
+ }
+ return PrintDict(valDict, indentLevel)
+}
+
// PrintDict returns a starlark-compatible string containing a dictionary with string keys and
// values printed with no additional formatting.
func PrintDict(dict map[string]string, indentLevel int) string {
diff --git a/starlark_import/Android.bp b/starlark_import/Android.bp
new file mode 100644
index 0000000..b43217b
--- /dev/null
+++ b/starlark_import/Android.bp
@@ -0,0 +1,36 @@
+// Copyright 2023 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-starlark",
+ pkgPath: "android/soong/starlark_import",
+ srcs: [
+ "starlark_import.go",
+ "unmarshal.go",
+ ],
+ testSrcs: [
+ "starlark_import_test.go",
+ "unmarshal_test.go",
+ ],
+ deps: [
+ "go-starlark-starlark",
+ "go-starlark-starlarkstruct",
+ "go-starlark-starlarkjson",
+ "go-starlark-starlarktest",
+ ],
+}
diff --git a/starlark_import/README.md b/starlark_import/README.md
new file mode 100644
index 0000000..e444759
--- /dev/null
+++ b/starlark_import/README.md
@@ -0,0 +1,14 @@
+# starlark_import package
+
+This allows soong to read constant information from starlark files. At package initialization
+time, soong will read `build/bazel/constants_exported_to_soong.bzl`, and then make the
+variables from that file available via `starlark_import.GetStarlarkValue()`. So to import
+a new variable, it must be added to `constants_exported_to_soong.bzl` and then it can
+be accessed by name.
+
+Only constant information can be read, since this is not a full bazel execution but a
+standalone starlark interpreter. This means you can't use bazel contructs like `rule`,
+`provider`, `select`, `glob`, etc.
+
+All starlark files that were loaded must be added as ninja deps that cause soong to rerun.
+The loaded files can be retrieved via `starlark_import.GetNinjaDeps()`.
diff --git a/starlark_import/starlark_import.go b/starlark_import/starlark_import.go
new file mode 100644
index 0000000..ebe4247
--- /dev/null
+++ b/starlark_import/starlark_import.go
@@ -0,0 +1,306 @@
+// Copyright 2023 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 starlark_import
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+
+ "go.starlark.net/starlark"
+ "go.starlark.net/starlarkjson"
+ "go.starlark.net/starlarkstruct"
+)
+
+func init() {
+ go func() {
+ startTime := time.Now()
+ v, d, err := runStarlarkFile("//build/bazel/constants_exported_to_soong.bzl")
+ endTime := time.Now()
+ //fmt.Fprintf(os.Stderr, "starlark run time: %s\n", endTime.Sub(startTime).String())
+ globalResult.Set(starlarkResult{
+ values: v,
+ ninjaDeps: d,
+ err: err,
+ startTime: startTime,
+ endTime: endTime,
+ })
+ }()
+}
+
+type starlarkResult struct {
+ values starlark.StringDict
+ ninjaDeps []string
+ err error
+ startTime time.Time
+ endTime time.Time
+}
+
+// setOnce wraps a value and exposes Set() and Get() accessors for it.
+// The Get() calls will block until a Set() has been called.
+// A second call to Set() will panic.
+// setOnce must be created using newSetOnce()
+type setOnce[T any] struct {
+ value T
+ lock sync.Mutex
+ wg sync.WaitGroup
+ isSet bool
+}
+
+func (o *setOnce[T]) Set(value T) {
+ o.lock.Lock()
+ defer o.lock.Unlock()
+ if o.isSet {
+ panic("Value already set")
+ }
+
+ o.value = value
+ o.isSet = true
+ o.wg.Done()
+}
+
+func (o *setOnce[T]) Get() T {
+ if !o.isSet {
+ o.wg.Wait()
+ }
+ return o.value
+}
+
+func newSetOnce[T any]() *setOnce[T] {
+ result := &setOnce[T]{}
+ result.wg.Add(1)
+ return result
+}
+
+var globalResult = newSetOnce[starlarkResult]()
+
+func GetStarlarkValue[T any](key string) (T, error) {
+ result := globalResult.Get()
+ if result.err != nil {
+ var zero T
+ return zero, result.err
+ }
+ if !result.values.Has(key) {
+ var zero T
+ return zero, fmt.Errorf("a starlark variable by that name wasn't found, did you update //build/bazel/constants_exported_to_soong.bzl?")
+ }
+ return Unmarshal[T](result.values[key])
+}
+
+func GetNinjaDeps() ([]string, error) {
+ result := globalResult.Get()
+ if result.err != nil {
+ return nil, result.err
+ }
+ return result.ninjaDeps, nil
+}
+
+func getTopDir() (string, error) {
+ // It's hard to communicate the top dir to this package in any other way than reading the
+ // arguments directly, because we need to know this at package initialization time. Many
+ // soong constants that we'd like to read from starlark are initialized during package
+ // initialization.
+ for i, arg := range os.Args {
+ if arg == "--top" {
+ if i < len(os.Args)-1 && os.Args[i+1] != "" {
+ return os.Args[i+1], nil
+ }
+ }
+ }
+
+ // When running tests, --top is not passed. Instead, search for the top dir manually
+ cwd, err := os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ for cwd != "/" {
+ if _, err := os.Stat(filepath.Join(cwd, "build/soong/soong_ui.bash")); err == nil {
+ return cwd, nil
+ }
+ cwd = filepath.Dir(cwd)
+ }
+ return "", fmt.Errorf("could not find top dir")
+}
+
+const callerDirKey = "callerDir"
+
+type modentry struct {
+ globals starlark.StringDict
+ err error
+}
+
+func unsupportedMethod(t *starlark.Thread, fn *starlark.Builtin, _ starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
+ return nil, fmt.Errorf("%sthis file is read by soong, and must therefore be pure starlark and include only constant information. %q is not allowed", t.CallStack().String(), fn.Name())
+}
+
+var builtins = starlark.StringDict{
+ "aspect": starlark.NewBuiltin("aspect", unsupportedMethod),
+ "glob": starlark.NewBuiltin("glob", unsupportedMethod),
+ "json": starlarkjson.Module,
+ "provider": starlark.NewBuiltin("provider", unsupportedMethod),
+ "rule": starlark.NewBuiltin("rule", unsupportedMethod),
+ "struct": starlark.NewBuiltin("struct", starlarkstruct.Make),
+ "select": starlark.NewBuiltin("select", unsupportedMethod),
+ "transition": starlark.NewBuiltin("transition", unsupportedMethod),
+}
+
+// Takes a module name (the first argument to the load() function) and returns the path
+// it's trying to load, stripping out leading //, and handling leading :s.
+func cleanModuleName(moduleName string, callerDir string) (string, error) {
+ if strings.Count(moduleName, ":") > 1 {
+ return "", fmt.Errorf("at most 1 colon must be present in starlark path: %s", moduleName)
+ }
+
+ // We don't have full support for external repositories, but at least support skylib's dicts.
+ if moduleName == "@bazel_skylib//lib:dicts.bzl" {
+ return "external/bazel-skylib/lib/dicts.bzl", nil
+ }
+
+ localLoad := false
+ if strings.HasPrefix(moduleName, "@//") {
+ moduleName = moduleName[3:]
+ } else if strings.HasPrefix(moduleName, "//") {
+ moduleName = moduleName[2:]
+ } else if strings.HasPrefix(moduleName, ":") {
+ moduleName = moduleName[1:]
+ localLoad = true
+ } else {
+ return "", fmt.Errorf("load path must start with // or :")
+ }
+
+ if ix := strings.LastIndex(moduleName, ":"); ix >= 0 {
+ moduleName = moduleName[:ix] + string(os.PathSeparator) + moduleName[ix+1:]
+ }
+
+ if filepath.Clean(moduleName) != moduleName {
+ return "", fmt.Errorf("load path must be clean, found: %s, expected: %s", moduleName, filepath.Clean(moduleName))
+ }
+ if strings.HasPrefix(moduleName, "../") {
+ return "", fmt.Errorf("load path must not start with ../: %s", moduleName)
+ }
+ if strings.HasPrefix(moduleName, "/") {
+ return "", fmt.Errorf("load path starts with /, use // for a absolute path: %s", moduleName)
+ }
+
+ if localLoad {
+ return filepath.Join(callerDir, moduleName), nil
+ }
+
+ return moduleName, nil
+}
+
+// loader implements load statement. The format of the loaded module URI is
+//
+// [//path]:base
+//
+// The file path is $ROOT/path/base if path is present, <caller_dir>/base otherwise.
+func loader(thread *starlark.Thread, module string, topDir string, moduleCache map[string]*modentry, moduleCacheLock *sync.Mutex, filesystem map[string]string) (starlark.StringDict, error) {
+ modulePath, err := cleanModuleName(module, thread.Local(callerDirKey).(string))
+ if err != nil {
+ return nil, err
+ }
+ moduleCacheLock.Lock()
+ e, ok := moduleCache[modulePath]
+ if e == nil {
+ if ok {
+ moduleCacheLock.Unlock()
+ return nil, fmt.Errorf("cycle in load graph")
+ }
+
+ // Add a placeholder to indicate "load in progress".
+ moduleCache[modulePath] = nil
+ moduleCacheLock.Unlock()
+
+ childThread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
+
+ // Cheating for the sake of testing:
+ // propagate starlarktest's Reporter key, otherwise testing
+ // the load function may cause panic in starlarktest code.
+ const testReporterKey = "Reporter"
+ if v := thread.Local(testReporterKey); v != nil {
+ childThread.SetLocal(testReporterKey, v)
+ }
+
+ childThread.SetLocal(callerDirKey, filepath.Dir(modulePath))
+
+ if filesystem != nil {
+ globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), filesystem[modulePath], builtins)
+ e = &modentry{globals, err}
+ } else {
+ globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), nil, builtins)
+ e = &modentry{globals, err}
+ }
+
+ // Update the cache.
+ moduleCacheLock.Lock()
+ moduleCache[modulePath] = e
+ }
+ moduleCacheLock.Unlock()
+ return e.globals, e.err
+}
+
+// Run runs the given starlark file and returns its global variables and a list of all starlark
+// files that were loaded. The top dir for starlark's // is found via getTopDir().
+func runStarlarkFile(filename string) (starlark.StringDict, []string, error) {
+ topDir, err := getTopDir()
+ if err != nil {
+ return nil, nil, err
+ }
+ return runStarlarkFileWithFilesystem(filename, topDir, nil)
+}
+
+func runStarlarkFileWithFilesystem(filename string, topDir string, filesystem map[string]string) (starlark.StringDict, []string, error) {
+ if !strings.HasPrefix(filename, "//") && !strings.HasPrefix(filename, ":") {
+ filename = "//" + filename
+ }
+ filename, err := cleanModuleName(filename, "")
+ if err != nil {
+ return nil, nil, err
+ }
+ moduleCache := make(map[string]*modentry)
+ moduleCache[filename] = nil
+ moduleCacheLock := &sync.Mutex{}
+ mainThread := &starlark.Thread{
+ Name: "main",
+ Print: func(_ *starlark.Thread, msg string) {
+ // Ignore prints
+ },
+ Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
+ return loader(thread, module, topDir, moduleCache, moduleCacheLock, filesystem)
+ },
+ }
+ mainThread.SetLocal(callerDirKey, filepath.Dir(filename))
+
+ var result starlark.StringDict
+ if filesystem != nil {
+ result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), filesystem[filename], builtins)
+ } else {
+ result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), nil, builtins)
+ }
+ return result, sortedStringKeys(moduleCache), err
+}
+
+func sortedStringKeys(m map[string]*modentry) []string {
+ s := make([]string, 0, len(m))
+ for k := range m {
+ s = append(s, k)
+ }
+ sort.Strings(s)
+ return s
+}
diff --git a/starlark_import/starlark_import_test.go b/starlark_import/starlark_import_test.go
new file mode 100644
index 0000000..8a58e3b
--- /dev/null
+++ b/starlark_import/starlark_import_test.go
@@ -0,0 +1,122 @@
+// Copyright 2023 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 starlark_import
+
+import (
+ "strings"
+ "testing"
+
+ "go.starlark.net/starlark"
+)
+
+func TestBasic(t *testing.T) {
+ globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+ "a.bzl": `
+my_string = "hello, world!"
+`})
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if globals["my_string"].(starlark.String) != "hello, world!" {
+ t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+ }
+}
+
+func TestLoad(t *testing.T) {
+ globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+ "a.bzl": `
+load("//b.bzl", _b_string = "my_string")
+my_string = "hello, " + _b_string
+`,
+ "b.bzl": `
+my_string = "world!"
+`})
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if globals["my_string"].(starlark.String) != "hello, world!" {
+ t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+ }
+}
+
+func TestLoadRelative(t *testing.T) {
+ globals, ninjaDeps, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+ "a.bzl": `
+load(":b.bzl", _b_string = "my_string")
+load("//foo/c.bzl", _c_string = "my_string")
+my_string = "hello, " + _b_string
+c_string = _c_string
+`,
+ "b.bzl": `
+my_string = "world!"
+`,
+ "foo/c.bzl": `
+load(":d.bzl", _d_string = "my_string")
+my_string = "hello, " + _d_string
+`,
+ "foo/d.bzl": `
+my_string = "world!"
+`})
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if globals["my_string"].(starlark.String) != "hello, world!" {
+ t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
+ }
+
+ expectedNinjaDeps := []string{
+ "a.bzl",
+ "b.bzl",
+ "foo/c.bzl",
+ "foo/d.bzl",
+ }
+ if !slicesEqual(ninjaDeps, expectedNinjaDeps) {
+ t.Errorf("Expected %v ninja deps, got %v", expectedNinjaDeps, ninjaDeps)
+ }
+}
+
+func TestLoadCycle(t *testing.T) {
+ _, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
+ "a.bzl": `
+load(":b.bzl", _b_string = "my_string")
+my_string = "hello, " + _b_string
+`,
+ "b.bzl": `
+load(":a.bzl", _a_string = "my_string")
+my_string = "hello, " + _a_string
+`})
+ if err == nil || !strings.Contains(err.Error(), "cycle in load graph") {
+ t.Errorf("Expected cycle in load graph, got: %v", err)
+ return
+ }
+}
+
+func slicesEqual[T comparable](a []T, b []T) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/starlark_import/unmarshal.go b/starlark_import/unmarshal.go
new file mode 100644
index 0000000..1b54437
--- /dev/null
+++ b/starlark_import/unmarshal.go
@@ -0,0 +1,288 @@
+// Copyright 2023 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 starlark_import
+
+import (
+ "fmt"
+ "math"
+ "reflect"
+ "unsafe"
+
+ "go.starlark.net/starlark"
+ "go.starlark.net/starlarkstruct"
+)
+
+func Unmarshal[T any](value starlark.Value) (T, error) {
+ var zero T
+ x, err := UnmarshalReflect(value, reflect.TypeOf(zero))
+ return x.Interface().(T), err
+}
+
+func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, error) {
+ zero := reflect.Zero(ty)
+ var result reflect.Value
+ if ty.Kind() == reflect.Interface {
+ var err error
+ ty, err = typeOfStarlarkValue(value)
+ if err != nil {
+ return zero, err
+ }
+ }
+ if ty.Kind() == reflect.Map {
+ result = reflect.MakeMap(ty)
+ } else {
+ result = reflect.Indirect(reflect.New(ty))
+ }
+
+ switch v := value.(type) {
+ case starlark.String:
+ if result.Type().Kind() != reflect.String {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ result.SetString(v.GoString())
+ case starlark.Int:
+ signedValue, signedOk := v.Int64()
+ unsignedValue, unsignedOk := v.Uint64()
+ switch result.Type().Kind() {
+ case reflect.Int64:
+ if !signedOk {
+ return zero, fmt.Errorf("starlark int didn't fit in go int64")
+ }
+ result.SetInt(signedValue)
+ case reflect.Int32:
+ if !signedOk || signedValue > math.MaxInt32 || signedValue < math.MinInt32 {
+ return zero, fmt.Errorf("starlark int didn't fit in go int32")
+ }
+ result.SetInt(signedValue)
+ case reflect.Int16:
+ if !signedOk || signedValue > math.MaxInt16 || signedValue < math.MinInt16 {
+ return zero, fmt.Errorf("starlark int didn't fit in go int16")
+ }
+ result.SetInt(signedValue)
+ case reflect.Int8:
+ if !signedOk || signedValue > math.MaxInt8 || signedValue < math.MinInt8 {
+ return zero, fmt.Errorf("starlark int didn't fit in go int8")
+ }
+ result.SetInt(signedValue)
+ case reflect.Int:
+ if !signedOk || signedValue > math.MaxInt || signedValue < math.MinInt {
+ return zero, fmt.Errorf("starlark int didn't fit in go int")
+ }
+ result.SetInt(signedValue)
+ case reflect.Uint64:
+ if !unsignedOk {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint64")
+ }
+ result.SetUint(unsignedValue)
+ case reflect.Uint32:
+ if !unsignedOk || unsignedValue > math.MaxUint32 {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint32")
+ }
+ result.SetUint(unsignedValue)
+ case reflect.Uint16:
+ if !unsignedOk || unsignedValue > math.MaxUint16 {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint16")
+ }
+ result.SetUint(unsignedValue)
+ case reflect.Uint8:
+ if !unsignedOk || unsignedValue > math.MaxUint8 {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint8")
+ }
+ result.SetUint(unsignedValue)
+ case reflect.Uint:
+ if !unsignedOk || unsignedValue > math.MaxUint {
+ return zero, fmt.Errorf("starlark int didn't fit in go uint")
+ }
+ result.SetUint(unsignedValue)
+ default:
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ case starlark.Float:
+ f := float64(v)
+ switch result.Type().Kind() {
+ case reflect.Float64:
+ result.SetFloat(f)
+ case reflect.Float32:
+ if f > math.MaxFloat32 || f < -math.MaxFloat32 {
+ return zero, fmt.Errorf("starlark float didn't fit in go float32")
+ }
+ result.SetFloat(f)
+ default:
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ case starlark.Bool:
+ if result.Type().Kind() != reflect.Bool {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ result.SetBool(bool(v))
+ case starlark.Tuple:
+ if result.Type().Kind() != reflect.Slice {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ elemType := result.Type().Elem()
+ // TODO: Add this grow call when we're on go 1.20
+ //result.Grow(v.Len())
+ for i := 0; i < v.Len(); i++ {
+ elem, err := UnmarshalReflect(v.Index(i), elemType)
+ if err != nil {
+ return zero, err
+ }
+ result = reflect.Append(result, elem)
+ }
+ case *starlark.List:
+ if result.Type().Kind() != reflect.Slice {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ elemType := result.Type().Elem()
+ // TODO: Add this grow call when we're on go 1.20
+ //result.Grow(v.Len())
+ for i := 0; i < v.Len(); i++ {
+ elem, err := UnmarshalReflect(v.Index(i), elemType)
+ if err != nil {
+ return zero, err
+ }
+ result = reflect.Append(result, elem)
+ }
+ case *starlark.Dict:
+ if result.Type().Kind() != reflect.Map {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ keyType := result.Type().Key()
+ valueType := result.Type().Elem()
+ for _, pair := range v.Items() {
+ key := pair.Index(0)
+ value := pair.Index(1)
+
+ unmarshalledKey, err := UnmarshalReflect(key, keyType)
+ if err != nil {
+ return zero, err
+ }
+ unmarshalledValue, err := UnmarshalReflect(value, valueType)
+ if err != nil {
+ return zero, err
+ }
+
+ result.SetMapIndex(unmarshalledKey, unmarshalledValue)
+ }
+ case *starlarkstruct.Struct:
+ if result.Type().Kind() != reflect.Struct {
+ return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
+ }
+ if result.NumField() != len(v.AttrNames()) {
+ return zero, fmt.Errorf("starlark struct and go struct have different number of fields (%d and %d)", len(v.AttrNames()), result.NumField())
+ }
+ for _, attrName := range v.AttrNames() {
+ attr, err := v.Attr(attrName)
+ if err != nil {
+ return zero, err
+ }
+
+ // TODO(b/279787235): this should probably support tags to rename the field
+ resultField := result.FieldByName(attrName)
+ if resultField == (reflect.Value{}) {
+ return zero, fmt.Errorf("starlark struct had field %s, but requested struct type did not", attrName)
+ }
+ // This hack allows us to change unexported fields
+ resultField = reflect.NewAt(resultField.Type(), unsafe.Pointer(resultField.UnsafeAddr())).Elem()
+ x, err := UnmarshalReflect(attr, resultField.Type())
+ if err != nil {
+ return zero, err
+ }
+ resultField.Set(x)
+ }
+ default:
+ return zero, fmt.Errorf("unimplemented starlark type: %s", value.Type())
+ }
+
+ return result, nil
+}
+
+func typeOfStarlarkValue(value starlark.Value) (reflect.Type, error) {
+ var err error
+ switch v := value.(type) {
+ case starlark.String:
+ return reflect.TypeOf(""), nil
+ case *starlark.List:
+ innerType := reflect.TypeOf("")
+ if v.Len() > 0 {
+ innerType, err = typeOfStarlarkValue(v.Index(0))
+ if err != nil {
+ return nil, err
+ }
+ }
+ for i := 1; i < v.Len(); i++ {
+ innerTypeI, err := typeOfStarlarkValue(v.Index(i))
+ if err != nil {
+ return nil, err
+ }
+ if innerType != innerTypeI {
+ return nil, fmt.Errorf("List must contain elements of entirely the same type, found %v and %v", innerType, innerTypeI)
+ }
+ }
+ return reflect.SliceOf(innerType), nil
+ case *starlark.Dict:
+ keyType := reflect.TypeOf("")
+ valueType := reflect.TypeOf("")
+ keys := v.Keys()
+ if v.Len() > 0 {
+ firstKey := keys[0]
+ keyType, err = typeOfStarlarkValue(firstKey)
+ if err != nil {
+ return nil, err
+ }
+ firstValue, found, err := v.Get(firstKey)
+ if !found {
+ err = fmt.Errorf("value not found")
+ }
+ if err != nil {
+ return nil, err
+ }
+ valueType, err = typeOfStarlarkValue(firstValue)
+ if err != nil {
+ return nil, err
+ }
+ }
+ for _, key := range keys {
+ keyTypeI, err := typeOfStarlarkValue(key)
+ if err != nil {
+ return nil, err
+ }
+ if keyType != keyTypeI {
+ return nil, fmt.Errorf("dict must contain elements of entirely the same type, found %v and %v", keyType, keyTypeI)
+ }
+ value, found, err := v.Get(key)
+ if !found {
+ err = fmt.Errorf("value not found")
+ }
+ if err != nil {
+ return nil, err
+ }
+ valueTypeI, err := typeOfStarlarkValue(value)
+ if valueType.Kind() != reflect.Interface && valueTypeI != valueType {
+ // If we see conflicting value types, change the result value type to an empty interface
+ valueType = reflect.TypeOf([]interface{}{}).Elem()
+ }
+ }
+ return reflect.MapOf(keyType, valueType), nil
+ case starlark.Int:
+ return reflect.TypeOf(0), nil
+ case starlark.Float:
+ return reflect.TypeOf(0.0), nil
+ case starlark.Bool:
+ return reflect.TypeOf(true), nil
+ default:
+ return nil, fmt.Errorf("unimplemented starlark type: %s", value.Type())
+ }
+}
diff --git a/starlark_import/unmarshal_test.go b/starlark_import/unmarshal_test.go
new file mode 100644
index 0000000..ee7a9e3
--- /dev/null
+++ b/starlark_import/unmarshal_test.go
@@ -0,0 +1,133 @@
+// Copyright 2023 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 starlark_import
+
+import (
+ "reflect"
+ "testing"
+
+ "go.starlark.net/starlark"
+)
+
+func createStarlarkValue(t *testing.T, code string) starlark.Value {
+ t.Helper()
+ result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, builtins)
+ if err != nil {
+ panic(err)
+ }
+ return result["x"]
+}
+
+func TestUnmarshallConcreteType(t *testing.T) {
+ x, err := Unmarshal[string](createStarlarkValue(t, `"foo"`))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if x != "foo" {
+ t.Errorf(`Expected "foo", got %q`, x)
+ }
+}
+
+func TestUnmarshallConcreteTypeWithInterfaces(t *testing.T) {
+ x, err := Unmarshal[map[string]map[string]interface{}](createStarlarkValue(t,
+ `{"foo": {"foo2": "foo3"}, "bar": {"bar2": ["bar3"]}}`))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ expected := map[string]map[string]interface{}{
+ "foo": {"foo2": "foo3"},
+ "bar": {"bar2": []string{"bar3"}},
+ }
+ if !reflect.DeepEqual(x, expected) {
+ t.Errorf(`Expected %v, got %v`, expected, x)
+ }
+}
+
+func TestUnmarshall(t *testing.T) {
+ testCases := []struct {
+ input string
+ expected interface{}
+ }{
+ {
+ input: `"foo"`,
+ expected: "foo",
+ },
+ {
+ input: `5`,
+ expected: 5,
+ },
+ {
+ input: `["foo", "bar"]`,
+ expected: []string{"foo", "bar"},
+ },
+ {
+ input: `("foo", "bar")`,
+ expected: []string{"foo", "bar"},
+ },
+ {
+ input: `("foo",5)`,
+ expected: []interface{}{"foo", 5},
+ },
+ {
+ input: `{"foo": 5, "bar": 10}`,
+ expected: map[string]int{"foo": 5, "bar": 10},
+ },
+ {
+ input: `{"foo": ["qux"], "bar": []}`,
+ expected: map[string][]string{"foo": {"qux"}, "bar": nil},
+ },
+ {
+ input: `struct(Foo="foo", Bar=5)`,
+ expected: struct {
+ Foo string
+ Bar int
+ }{Foo: "foo", Bar: 5},
+ },
+ {
+ // Unexported fields version of the above
+ input: `struct(foo="foo", bar=5)`,
+ expected: struct {
+ foo string
+ bar int
+ }{foo: "foo", bar: 5},
+ },
+ {
+ input: `{"foo": "foo2", "bar": ["bar2"], "baz": 5, "qux": {"qux2": "qux3"}, "quux": {"quux2": "quux3", "quux4": 5}}`,
+ expected: map[string]interface{}{
+ "foo": "foo2",
+ "bar": []string{"bar2"},
+ "baz": 5,
+ "qux": map[string]string{"qux2": "qux3"},
+ "quux": map[string]interface{}{
+ "quux2": "quux3",
+ "quux4": 5,
+ },
+ },
+ },
+ }
+
+ for _, tc := range testCases {
+ x, err := UnmarshalReflect(createStarlarkValue(t, tc.input), reflect.TypeOf(tc.expected))
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(x.Interface(), tc.expected) {
+ t.Errorf(`Expected %#v, got %#v`, tc.expected, x.Interface())
+ }
+ }
+}
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 5935247..5fc05f8 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -207,8 +207,8 @@
function test_soong_build_rerun_iff_environment_changes() {
setup
- mkdir -p cherry
- cat > cherry/Android.bp <<'EOF'
+ mkdir -p build/soong/cherry
+ cat > build/soong/cherry/Android.bp <<'EOF'
bootstrap_go_package {
name: "cherry",
pkgPath: "android/soong/cherry",
@@ -224,7 +224,7 @@
}
EOF
- cat > cherry/cherry.go <<'EOF'
+ cat > build/soong/cherry/cherry.go <<'EOF'
package cherry
import (
@@ -317,8 +317,8 @@
run_soong
local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
- mkdir -p a
- cat > a/Android.bp <<'EOF'
+ mkdir -p vendor/foo/picard
+ cat > vendor/foo/picard/Android.bp <<'EOF'
bootstrap_go_package {
name: "picard-soong-rules",
pkgPath: "android/soong/picard",
@@ -334,7 +334,7 @@
}
EOF
- cat > a/picard.go <<'EOF'
+ cat > vendor/foo/picard/picard.go <<'EOF'
package picard
import (
@@ -390,11 +390,11 @@
function test_glob_during_bootstrapping() {
setup
- mkdir -p a
- cat > a/Android.bp <<'EOF'
+ mkdir -p build/soong/picard
+ cat > build/soong/picard/Android.bp <<'EOF'
build=["foo*.bp"]
EOF
- cat > a/fooa.bp <<'EOF'
+ cat > build/soong/picard/fooa.bp <<'EOF'
bootstrap_go_package {
name: "picard-soong-rules",
pkgPath: "android/soong/picard",
@@ -410,7 +410,7 @@
}
EOF
- cat > a/picard.go <<'EOF'
+ cat > build/soong/picard/picard.go <<'EOF'
package picard
import (
@@ -459,7 +459,7 @@
grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
- cat > a/foob.bp <<'EOF'
+ cat > build/soong/picard/foob.bp <<'EOF'
bootstrap_go_package {
name: "worf-soong-rules",
pkgPath: "android/soong/worf",
@@ -476,7 +476,7 @@
}
EOF
- cat > a/worf.go <<'EOF'
+ cat > build/soong/picard/worf.go <<'EOF'
package worf
import "android/soong/picard"
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 68d7f8d..71e6af0 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -53,6 +53,20 @@
if [[ "$buildfile_mtime1" != "$buildfile_mtime2" ]]; then
fail "BUILD.bazel was updated even though contents are same"
fi
+
+ # Force bp2build to rerun by updating the timestamp of the constants_exported_to_soong.bzl file.
+ touch build/bazel/constants_exported_to_soong.bzl
+
+ run_soong bp2build
+ local -r buildfile_mtime3=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
+ local -r marker_mtime3=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+
+ if [[ "$marker_mtime2" == "$marker_mtime3" ]]; then
+ fail "Expected bp2build marker file to change"
+ fi
+ if [[ "$buildfile_mtime2" != "$buildfile_mtime3" ]]; then
+ fail "BUILD.bazel was updated even though contents are same"
+ fi
}
# Tests that blueprint files that are deleted are not present when the
diff --git a/tests/dcla_apex_comparison_test.sh b/tests/dcla_apex_comparison_test.sh
index 97ae97e..667dde0 100755
--- a/tests/dcla_apex_comparison_test.sh
+++ b/tests/dcla_apex_comparison_test.sh
@@ -45,6 +45,11 @@
com.android.tethering
)
+BAZEL_TARGETS=(
+ //packages/modules/adb/apex:com.android.adbd
+ //frameworks/av/apex:com.android.media.swcodec
+)
+
DCLA_LIBS=(
libbase.so
libc++.so
@@ -76,6 +81,10 @@
############
OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+function call_bazel() {
+ build/bazel/bin/bazel $@
+}
+
function cleanup {
rm -rf "${OUTPUT_DIR}"
}
@@ -87,7 +96,9 @@
function extract_dcla_libs() {
local product=$1; shift
- for module in "${MODULES[@]}"; do
+ local modules=("$@"); shift
+
+ for module in "${modules[@]}"; do
local apex="${OUTPUT_DIR}/${product}/${module}.apex"
local extract_dir="${OUTPUT_DIR}/${product}/${module}/extract"
@@ -97,11 +108,12 @@
function compare_dcla_libs() {
local product=$1; shift
+ local modules=("$@"); shift
for lib in "${DCLA_LIBS[@]}"; do
for arch in lib lib64; do
local prev_sha=""
- for module in "${MODULES[@]}"; do
+ for module in "${modules[@]}"; do
local file="${OUTPUT_DIR}/${product}/${module}/extract/${arch}/${lib}"
if [[ ! -f "${file}" ]]; then
# not all libs are present in a module
@@ -112,7 +124,7 @@
sha="${sha% *}"
if [ "${prev_sha}" == "" ]; then
prev_sha="${sha}"
- elif [ "${sha}" != "${prev_sha}" ] && { [ "${lib}" != "libcrypto.so" ] || [ "${module}" != "com.android.tethering" ]; }; then
+ elif [ "${sha}" != "${prev_sha}" ] && { [ "${lib}" != "libcrypto.so" ] || [[ "${module}" != *"com.android.tethering" ]]; }; then
echo "Test failed, ${lib} has different hash value"
exit 1
fi
@@ -131,8 +143,22 @@
--product "${product}" \
--dist_dir "${OUTPUT_DIR}/${product}"
- extract_dcla_libs "${product}"
- compare_dcla_libs "${product}"
+ bazel_apexes=()
+ if [[ -n ${TEST_BAZEL+x} ]] && [ "${TEST_BAZEL}" = true ]; then
+ export TARGET_PRODUCT="${product/module/aosp}"
+ call_bazel build --config=bp2build --config=ci --config=android "${BAZEL_TARGETS[@]}"
+ for target in "${BAZEL_TARGETS[@]}"; do
+ apex_path="$(realpath $(call_bazel cquery --config=bp2build --config=android --config=ci --output=files $target))"
+ mkdir -p ${OUTPUT_DIR}/${product}
+ bazel_apex="bazel_$(basename $apex_path)"
+ mv $apex_path ${OUTPUT_DIR}/${product}/${bazel_apex}
+ bazel_apexes+=(${bazel_apex%".apex"})
+ done
+ fi
+
+ all_modeuls=(${MODULES[@]} ${bazel_apexes[@]})
+ extract_dcla_libs "${product}" "${all_modeuls[@]}"
+ compare_dcla_libs "${product}" "${all_modeuls[@]}"
done
echo "Test passed"
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
index 05d3a66..ca63fdf 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -eu
+#!/bin/bash
set -o pipefail
@@ -88,12 +88,12 @@
fail "Bazel actions not found for force-enabled module"
fi
- local exit_code=`run_soong --bazel-force-enabled-modules=unenabled-touch-file nothing`
+ unused=`run_soong --bazel-force-enabled-modules=unenabled-touch-file --ensure-allowlist-integrity nothing >/dev/null`
- if [[ $exit_code -ne 1 ]]; then
+ if [[ $? -ne 1 ]]; then
fail "Expected failure due to force-enabling an unenabled module "
fi
}
-scan_and_run_tests
\ No newline at end of file
+scan_and_run_tests
diff --git a/tests/persistent_bazel_test.sh b/tests/persistent_bazel_test.sh
index 4e2982a..9b7b58f 100755
--- a/tests/persistent_bazel_test.sh
+++ b/tests/persistent_bazel_test.sh
@@ -73,8 +73,8 @@
USE_PERSISTENT_BAZEL=1 run_soong nothing 1>out/failurelog.txt 2>&1 && fail "Expected build failure" || true
- if ! grep -sq "'build/bazel/rules' is not a package" out/failurelog.txt ; then
- fail "Expected error to contain 'build/bazel/rules' is not a package, instead got:\n$(cat out/failurelog.txt)"
+ if ! grep -sq "cannot load //build/bazel/rules/common/api_constants.bzl" out/failurelog.txt ; then
+ fail "Expected error to contain 'cannot load //build/bazel/rules/common/api_constants.bzl', instead got:\n$(cat out/failurelog.txt)"
fi
kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index e1aa70c..db14bd4 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -15,8 +15,8 @@
# mock client.
"$TOP/build/soong/tests/apex_comparison_tests.sh"
"$TOP/build/soong/tests/apex_comparison_tests.sh" "module_arm64only"
-extra_build_params=--bazel-mode-staging "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
-BUILD_BROKEN_DISABLE_BAZEL=true "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
+TEST_BAZEL=true extra_build_params=--bazel-mode-staging "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
+#BUILD_BROKEN_DISABLE_BAZEL=true "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
diff --git a/tradefed/suite_harness/tradefed_binary.go b/tradefed/suite_harness/tradefed_binary.go
index a421d8b..1ce94bc 100644
--- a/tradefed/suite_harness/tradefed_binary.go
+++ b/tradefed/suite_harness/tradefed_binary.go
@@ -78,7 +78,6 @@
// Add dependencies required by all tradefed_binary modules.
props.Libs = []string{
"tradefed",
- "tradefed-test-framework",
"loganalysis",
"compatibility-host-util",
}
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index b79754c..959ae4c 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -46,6 +46,7 @@
"soong-ui-tracer",
],
srcs: [
+ "bazel_metrics.go",
"build.go",
"cleanbuild.go",
"config.go",
diff --git a/ui/build/bazel_metrics.go b/ui/build/bazel_metrics.go
new file mode 100644
index 0000000..c0690c1
--- /dev/null
+++ b/ui/build/bazel_metrics.go
@@ -0,0 +1,135 @@
+// Copyright 2023 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 build
+
+// This file contains functionality to parse bazel profile data into
+// a bazel_metrics proto, defined in build/soong/ui/metrics/bazel_metrics_proto
+// These metrics are later uploaded in upload.go
+
+import (
+ "bufio"
+ "os"
+ "strconv"
+ "strings"
+
+ "android/soong/shared"
+ "google.golang.org/protobuf/proto"
+
+ bazel_metrics_proto "android/soong/ui/metrics/bazel_metrics_proto"
+)
+
+func parseTimingToNanos(str string) int64 {
+ millisString := removeDecimalPoint(str)
+ timingMillis, _ := strconv.ParseInt(millisString, 10, 64)
+ return timingMillis * 1000000
+}
+
+func parsePercentageToTenThousandths(str string) int32 {
+ percentageString := removeDecimalPoint(str)
+ //remove the % at the end of the string
+ percentage := strings.ReplaceAll(percentageString, "%", "")
+ percentagePortion, _ := strconv.ParseInt(percentage, 10, 32)
+ return int32(percentagePortion)
+}
+
+func removeDecimalPoint(numString string) string {
+ // The format is always 0.425 or 10.425
+ return strings.ReplaceAll(numString, ".", "")
+}
+
+func parseTotal(line string) int64 {
+ words := strings.Fields(line)
+ timing := words[3]
+ return parseTimingToNanos(timing)
+}
+
+func parsePhaseTiming(line string) bazel_metrics_proto.PhaseTiming {
+ words := strings.Fields(line)
+ getPhaseNameAndTimingAndPercentage := func([]string) (string, int64, int32) {
+ // Sample lines include:
+ // Total launch phase time 0.011 s 2.59%
+ // Total target pattern evaluation phase time 0.011 s 2.59%
+ var beginning int
+ var end int
+ for ind, word := range words {
+ if word == "Total" {
+ beginning = ind + 1
+ } else if beginning > 0 && word == "phase" {
+ end = ind
+ break
+ }
+ }
+ phaseName := strings.Join(words[beginning:end], " ")
+
+ // end is now "phase" - advance by 2 for timing and 4 for percentage
+ percentageString := words[end+4]
+ timingString := words[end+2]
+ timing := parseTimingToNanos(timingString)
+ percentagePortion := parsePercentageToTenThousandths(percentageString)
+ return phaseName, timing, percentagePortion
+ }
+
+ phaseName, timing, portion := getPhaseNameAndTimingAndPercentage(words)
+ phaseTiming := bazel_metrics_proto.PhaseTiming{}
+ phaseTiming.DurationNanos = &timing
+ phaseTiming.PortionOfBuildTime = &portion
+
+ phaseTiming.PhaseName = &phaseName
+ return phaseTiming
+}
+
+// This method takes a file created by bazel's --analyze-profile mode and
+// writes bazel metrics data to the provided filepath.
+func ProcessBazelMetrics(bazelProfileFile string, bazelMetricsFile string, ctx Context, config Config) {
+ if bazelProfileFile == "" {
+ return
+ }
+
+ readBazelProto := func(filepath string) bazel_metrics_proto.BazelMetrics {
+ //serialize the proto, write it
+ bazelMetrics := bazel_metrics_proto.BazelMetrics{}
+
+ file, err := os.ReadFile(filepath)
+ if err != nil {
+ ctx.Fatalln("Error reading metrics file\n", err)
+ }
+
+ scanner := bufio.NewScanner(strings.NewReader(string(file)))
+ scanner.Split(bufio.ScanLines)
+
+ var phaseTimings []*bazel_metrics_proto.PhaseTiming
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.HasPrefix(line, "Total run time") {
+ total := parseTotal(line)
+ bazelMetrics.Total = &total
+ } else if strings.HasPrefix(line, "Total") {
+ phaseTiming := parsePhaseTiming(line)
+ phaseTimings = append(phaseTimings, &phaseTiming)
+ }
+ }
+ bazelMetrics.PhaseTimings = phaseTimings
+
+ return bazelMetrics
+ }
+
+ if _, err := os.Stat(bazelProfileFile); err != nil {
+ // We can assume bazel didn't run if the profile doesn't exist
+ return
+ }
+ bazelProto := readBazelProto(bazelProfileFile)
+ bazelProto.ExitCode = proto.Int32(config.bazelExitCode)
+ shared.Save(&bazelProto, bazelMetricsFile)
+}
diff --git a/ui/build/config.go b/ui/build/config.go
index bf4aec9..8ec9680 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -67,28 +67,30 @@
logsPrefix string
// From the arguments
- parallel int
- keepGoing int
- verbose bool
- checkbuild bool
- dist bool
- jsonModuleGraph bool
- apiBp2build bool // Generate BUILD files for Soong modules that contribute APIs
- bp2build bool
- queryview bool
- reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
- soongDocs bool
- multitreeBuild bool // This is a multitree build.
- skipConfig bool
- skipKati bool
- skipKatiNinja bool
- skipSoong bool
- skipNinja bool
- skipSoongTests bool
- searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces
- skipMetricsUpload bool
- buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time
- buildFromTextStub bool
+ parallel int
+ keepGoing int
+ verbose bool
+ checkbuild bool
+ dist bool
+ jsonModuleGraph bool
+ apiBp2build bool // Generate BUILD files for Soong modules that contribute APIs
+ bp2build bool
+ queryview bool
+ reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
+ soongDocs bool
+ multitreeBuild bool // This is a multitree build.
+ skipConfig bool
+ skipKati bool
+ skipKatiNinja bool
+ skipSoong bool
+ skipNinja bool
+ skipSoongTests bool
+ searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces
+ skipMetricsUpload bool
+ buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time
+ buildFromTextStub bool
+ ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
+ bazelExitCode int32 // For b-runs - necessary for updating NonZeroExit
// From the product config
katiArgs []string
@@ -297,11 +299,12 @@
return true
}
-func UploadOnlyConfig(ctx Context, _ ...string) Config {
+func UploadOnlyConfig(ctx Context, args ...string) Config {
ret := &configImpl{
environ: OsEnvironment(),
sandboxConfig: &SandboxConfig{},
}
+ ret.parseArgs(ctx, args)
srcDir := absPath(ctx, ".")
bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
if err := loadEnvConfig(ctx, ret, bc); err != nil {
@@ -813,9 +816,6 @@
// by a previous build.
c.skipConfig = true
c.skipKati = true
- } else if arg == "--skip-kati" {
- // TODO: remove --skip-kati once module builds have been migrated to --song-only
- c.skipKati = true
} else if arg == "--soong-only" {
c.skipKati = true
c.skipKatiNinja = true
@@ -883,6 +883,16 @@
} else {
ctx.Fatalf("Error parsing build-time-started-unix-millis", err)
}
+ } else if arg == "--ensure-allowlist-integrity" {
+ c.ensureAllowlistIntegrity = true
+ } else if strings.HasPrefix(arg, "--bazel-exit-code=") {
+ bazelExitCodeStr := strings.TrimPrefix(arg, "--bazel-exit-code=")
+ val, err := strconv.Atoi(bazelExitCodeStr)
+ if err == nil {
+ c.bazelExitCode = int32(val)
+ } else {
+ ctx.Fatalf("Error parsing bazel-exit-code", err)
+ }
} else if len(arg) > 0 && arg[0] == '-' {
parseArgNum := func(def int) int {
if len(arg) > 2 {
@@ -1710,6 +1720,10 @@
return c.skipMetricsUpload
}
+func (c *configImpl) EnsureAllowlistIntegrity() bool {
+ return c.ensureAllowlistIntegrity
+}
+
// Returns a Time object if one was passed via a command-line flag.
// Otherwise returns the passed default.
func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time {
@@ -1719,6 +1733,10 @@
return time.UnixMilli(c.buildStartedTime)
}
+func (c *configImpl) BazelExitCode() int32 {
+ return c.bazelExitCode
+}
+
func GetMetricsUploader(topDir string, env *Environment) string {
if p, ok := env.Get("METRICS_UPLOADER"); ok {
metricsUploader := filepath.Join(topDir, p)
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 3f628cf..62079fe 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -87,6 +87,8 @@
"TEST_MAPPING",
// Bazel top-level file to mark a directory as a Bazel workspace.
"WORKSPACE",
+ // METADATA file of packages
+ "METADATA",
},
// Bazel Starlark configuration files and all .mk files for product/board configuration.
IncludeSuffixes: []string{".bzl", ".mk"},
@@ -189,6 +191,13 @@
ctx.Fatalf("Could not find OWNERS: %v", err)
}
+ // Recursively look for all METADATA files.
+ metadataFiles := f.FindNamedAt(".", "METADATA")
+ err = dumpListToFile(ctx, config, metadataFiles, filepath.Join(dumpDir, "METADATA.list"))
+ if err != nil {
+ ctx.Fatalf("Could not find METADATA: %v", err)
+ }
+
// Recursively look for all TEST_MAPPING files.
testMappings := f.FindNamedAt(".", "TEST_MAPPING")
err = dumpListToFile(ctx, config, testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 6479925..3b9d301 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -183,8 +183,6 @@
return
}
- ctx.Status.Status("Dumping rbe metrics...")
-
outputDir := config.rbeProxyLogsDir()
if outputDir == "" {
ctx.Fatal("RBE output dir variable not defined. Aborting metrics dumping.")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 9287731..18bf3b9 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -288,6 +288,9 @@
if config.buildFromTextStub {
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-text-stub")
}
+ if config.ensureAllowlistIntegrity {
+ mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--ensure-allowlist-integrity")
+ }
queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
// The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)
@@ -397,6 +400,8 @@
pbi.Inputs = append(pbi.Inputs,
config.Bp2BuildFilesMarkerFile(),
filepath.Join(config.FileListDir(), "bazel.list"))
+ case bp2buildFilesTag:
+ pbi.Inputs = append(pbi.Inputs, filepath.Join(config.FileListDir(), "METADATA.list"))
}
invocations = append(invocations, pbi)
}
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 9959e6f..9f14bdd 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -18,21 +18,16 @@
// another.
import (
- "bufio"
"fmt"
"io/ioutil"
"os"
"path/filepath"
- "strconv"
- "strings"
"time"
- "android/soong/shared"
"android/soong/ui/metrics"
"google.golang.org/protobuf/proto"
- bazel_metrics_proto "android/soong/ui/metrics/bazel_metrics_proto"
upload_proto "android/soong/ui/metrics/upload_proto"
)
@@ -78,113 +73,12 @@
return metricsFiles
}
-func parseTimingToNanos(str string) int64 {
- millisString := removeDecimalPoint(str)
- timingMillis, _ := strconv.ParseInt(millisString, 10, 64)
- return timingMillis * 1000000
-}
-
-func parsePercentageToTenThousandths(str string) int32 {
- percentageString := removeDecimalPoint(str)
- //remove the % at the end of the string
- percentage := strings.ReplaceAll(percentageString, "%", "")
- percentagePortion, _ := strconv.ParseInt(percentage, 10, 32)
- return int32(percentagePortion)
-}
-
-func removeDecimalPoint(numString string) string {
- // The format is always 0.425 or 10.425
- return strings.ReplaceAll(numString, ".", "")
-}
-
-func parseTotal(line string) int64 {
- words := strings.Fields(line)
- timing := words[3]
- return parseTimingToNanos(timing)
-}
-
-func parsePhaseTiming(line string) bazel_metrics_proto.PhaseTiming {
- words := strings.Fields(line)
- getPhaseNameAndTimingAndPercentage := func([]string) (string, int64, int32) {
- // Sample lines include:
- // Total launch phase time 0.011 s 2.59%
- // Total target pattern evaluation phase time 0.011 s 2.59%
- var beginning int
- var end int
- for ind, word := range words {
- if word == "Total" {
- beginning = ind + 1
- } else if beginning > 0 && word == "phase" {
- end = ind
- break
- }
- }
- phaseName := strings.Join(words[beginning:end], " ")
-
- // end is now "phase" - advance by 2 for timing and 4 for percentage
- percentageString := words[end+4]
- timingString := words[end+2]
- timing := parseTimingToNanos(timingString)
- percentagePortion := parsePercentageToTenThousandths(percentageString)
- return phaseName, timing, percentagePortion
- }
-
- phaseName, timing, portion := getPhaseNameAndTimingAndPercentage(words)
- phaseTiming := bazel_metrics_proto.PhaseTiming{}
- phaseTiming.DurationNanos = &timing
- phaseTiming.PortionOfBuildTime = &portion
-
- phaseTiming.PhaseName = &phaseName
- return phaseTiming
-}
-
-func processBazelMetrics(bazelProfileFile string, bazelMetricsFile string, ctx Context) {
- if bazelProfileFile == "" {
- return
- }
-
- readBazelProto := func(filepath string) bazel_metrics_proto.BazelMetrics {
- //serialize the proto, write it
- bazelMetrics := bazel_metrics_proto.BazelMetrics{}
-
- file, err := os.ReadFile(filepath)
- if err != nil {
- ctx.Fatalln("Error reading metrics file\n", err)
- }
-
- scanner := bufio.NewScanner(strings.NewReader(string(file)))
- scanner.Split(bufio.ScanLines)
-
- var phaseTimings []*bazel_metrics_proto.PhaseTiming
- for scanner.Scan() {
- line := scanner.Text()
- if strings.HasPrefix(line, "Total run time") {
- total := parseTotal(line)
- bazelMetrics.Total = &total
- } else if strings.HasPrefix(line, "Total") {
- phaseTiming := parsePhaseTiming(line)
- phaseTimings = append(phaseTimings, &phaseTiming)
- }
- }
- bazelMetrics.PhaseTimings = phaseTimings
-
- return bazelMetrics
- }
-
- if _, err := os.Stat(bazelProfileFile); err != nil {
- // We can assume bazel didn't run if the profile doesn't exist
- return
- }
- bazelProto := readBazelProto(bazelProfileFile)
- shared.Save(&bazelProto, bazelMetricsFile)
-}
-
// UploadMetrics uploads a set of metrics files to a server for analysis.
// The metrics files are first copied to a temporary directory
// and the uploader is then executed in the background to allow the user/system
// to continue working. Soong communicates to the uploader through the
// upload_proto raw protobuf file.
-func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, bazelProfileFile string, bazelMetricsFile string, paths ...string) {
+func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, paths ...string) {
ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
defer ctx.EndTrace()
@@ -194,7 +88,6 @@
return
}
- processBazelMetrics(bazelProfileFile, bazelMetricsFile, ctx)
// Several of the files might be directories.
metricsFiles := pruneMetricsFiles(paths)
if len(metricsFiles) == 0 {
diff --git a/ui/build/upload_test.go b/ui/build/upload_test.go
index 58d9237..1fcded9 100644
--- a/ui/build/upload_test.go
+++ b/ui/build/upload_test.go
@@ -166,7 +166,7 @@
metricsUploader: tt.uploader,
}}
- UploadMetrics(ctx, config, false, time.Now(), "out/bazel_metrics.txt", "out/bazel_metrics.pb", metricsFiles...)
+ UploadMetrics(ctx, config, false, time.Now(), metricsFiles...)
})
}
}
@@ -221,7 +221,7 @@
metricsUploader: "echo",
}}
- UploadMetrics(ctx, config, true, time.Now(), "", "", metricsFile)
+ UploadMetrics(ctx, config, true, time.Now(), metricsFile)
t.Errorf("got nil, expecting %q as a failure", tt.expectedErr)
})
}
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
index f8b8fd6..bf5e80b 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
@@ -14,8 +14,8 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.28.0
-// protoc v3.21.7
+// protoc-gen-go v1.30.0
+// protoc v3.21.12
// source: bazel_metrics.proto
package bazel_metrics_proto
@@ -41,6 +41,7 @@
PhaseTimings []*PhaseTiming `protobuf:"bytes,1,rep,name=phase_timings,json=phaseTimings,proto3" json:"phase_timings,omitempty"`
Total *int64 `protobuf:"varint,2,opt,name=total,proto3,oneof" json:"total,omitempty"`
+ ExitCode *int32 `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3,oneof" json:"exit_code,omitempty"`
}
func (x *BazelMetrics) Reset() {
@@ -89,6 +90,13 @@
return 0
}
+func (x *BazelMetrics) GetExitCode() int32 {
+ if x != nil && x.ExitCode != nil {
+ return *x.ExitCode
+ }
+ return 0
+}
+
type PhaseTiming struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -161,15 +169,18 @@
0x0a, 0x13, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
- 0x22, 0x80, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+ 0x22, 0xb0, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e,
0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74,
0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67,
0x52, 0x0c, 0x70, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19,
0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52,
- 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x6f,
- 0x74, 0x61, 0x6c, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d,
+ 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x65, 0x78, 0x69,
+ 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x08,
+ 0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f,
+ 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63,
+ 0x6f, 0x64, 0x65, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d,
0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x70, 0x68, 0x61, 0x73, 0x65,
0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74,
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
index 57eed4c..9073080 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
@@ -20,6 +20,7 @@
message BazelMetrics {
repeated PhaseTiming phase_timings = 1;
optional int64 total = 2;
+ optional int32 exit_code = 3;
}
message PhaseTiming {
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 82d11ed..a282e20 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -228,7 +228,7 @@
m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second))
}
-func (m *Metrics) UpdateTotalRealTime(data []byte) error {
+func (m *Metrics) UpdateTotalRealTimeAndNonZeroExit(data []byte, bazelExitCode int32) error {
if err := proto.Unmarshal(data, &m.metrics); err != nil {
return fmt.Errorf("Failed to unmarshal proto", err)
}
@@ -236,6 +236,9 @@
endTime := uint64(time.Now().UnixNano())
*m.metrics.Total.RealTime = *proto.Uint64(endTime - startTime)
+
+ bazelError := bazelExitCode != 0
+ m.metrics.NonZeroExit = proto.Bool(bazelError)
return nil
}
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index def76aa..a2ccc20 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -78,6 +78,15 @@
return nil
}
+type explicitFile struct{}
+
+func (explicitFile) String() string { return `""` }
+
+func (explicitFile) Set(s string) error {
+ fileArgsBuilder.ExplicitPathInZip(s)
+ return nil
+}
+
type dir struct{}
func (dir) String() string { return `""` }
@@ -173,6 +182,7 @@
flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
flags.Var(&relativeRoot{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments")
flags.Var(&junkPaths{}, "j", "junk paths, zip files without directory names")
+ flags.Var(&explicitFile{}, "e", "filename to use in the zip file for the next -f argument")
flags.Parse(expandedArgs[1:])
diff --git a/zip/zip.go b/zip/zip.go
index 6f1a8ad..5e1a104 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -80,6 +80,7 @@
type FileArg struct {
PathPrefixInZip, SourcePrefixToStrip string
+ ExplicitPathInZip string
SourceFiles []string
JunkPaths bool
GlobDir string
@@ -124,6 +125,10 @@
arg := b.state
arg.SourceFiles = []string{name}
b.fileArgs = append(b.fileArgs, arg)
+
+ if b.state.ExplicitPathInZip != "" {
+ b.state.ExplicitPathInZip = ""
+ }
return b
}
@@ -189,6 +194,12 @@
return b
}
+// ExplicitPathInZip sets the path in the zip file for the next File call.
+func (b *FileArgsBuilder) ExplicitPathInZip(s string) *FileArgsBuilder {
+ b.state.ExplicitPathInZip = s
+ return b
+}
+
func (b *FileArgsBuilder) Error() error {
if b == nil {
return nil
@@ -425,7 +436,9 @@
var dest string
- if fa.JunkPaths {
+ if fa.ExplicitPathInZip != "" {
+ dest = fa.ExplicitPathInZip
+ } else if fa.JunkPaths {
dest = filepath.Base(src)
} else {
var err error
diff --git a/zip/zip_test.go b/zip/zip_test.go
index e7fdea8..c64c3f4 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -454,6 +454,60 @@
fhWithSHA256("c", fileC, zip.Deflate, sha256FileC),
},
},
+ {
+ name: "explicit path",
+ args: fileArgsBuilder().
+ ExplicitPathInZip("foo").
+ File("a/a/a").
+ File("a/a/b"),
+ compressionLevel: 9,
+
+ files: []zip.FileHeader{
+ fh("foo", fileA, zip.Deflate),
+ fh("a/a/b", fileB, zip.Deflate),
+ },
+ },
+ {
+ name: "explicit path with prefix",
+ args: fileArgsBuilder().
+ PathPrefixInZip("prefix").
+ ExplicitPathInZip("foo").
+ File("a/a/a").
+ File("a/a/b"),
+ compressionLevel: 9,
+
+ files: []zip.FileHeader{
+ fh("prefix/foo", fileA, zip.Deflate),
+ fh("prefix/a/a/b", fileB, zip.Deflate),
+ },
+ },
+ {
+ name: "explicit path with glob",
+ args: fileArgsBuilder().
+ ExplicitPathInZip("foo").
+ File("a/a/a*").
+ File("a/a/b"),
+ compressionLevel: 9,
+
+ files: []zip.FileHeader{
+ fh("foo", fileA, zip.Deflate),
+ fh("a/a/b", fileB, zip.Deflate),
+ },
+ },
+ {
+ name: "explicit path with junk paths",
+ args: fileArgsBuilder().
+ JunkPaths(true).
+ ExplicitPathInZip("foo/bar").
+ File("a/a/a*").
+ File("a/a/b"),
+ compressionLevel: 9,
+
+ files: []zip.FileHeader{
+ fh("foo/bar", fileA, zip.Deflate),
+ fh("b", fileB, zip.Deflate),
+ },
+ },
// errors
{
@@ -490,6 +544,22 @@
File("d/a/a"),
err: ConflictingFileError{},
},
+ {
+ name: "error explicit path conflicting",
+ args: fileArgsBuilder().
+ ExplicitPathInZip("foo").
+ File("a/a/a").
+ ExplicitPathInZip("foo").
+ File("a/a/b"),
+ err: ConflictingFileError{},
+ },
+ {
+ name: "error explicit path conflicting glob",
+ args: fileArgsBuilder().
+ ExplicitPathInZip("foo").
+ File("a/a/*"),
+ err: ConflictingFileError{},
+ },
}
for _, test := range testCases {