Merge "[WIP] Switch sh_test_host to unit_tests=true by default"
diff --git a/Android.bp b/Android.bp
index 45e661e..d6260b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -116,3 +116,13 @@
dex_bootjars {
name: "dex_bootjars",
}
+
+// Pseudo-test that's run on checkbuilds to ensure that get_clang_version can
+// parse cc/config/global.go.
+genrule {
+ name: "get_clang_version_test",
+ cmd: "$(location get_clang_version) > $(out)",
+ tools: ["get_clang_version"],
+ srcs: ["cc/config/global.go"],
+ out: ["clang-prebuilts-version.txt"],
+}
diff --git a/README.md b/README.md
index b7e93f4..10ddd73 100644
--- a/README.md
+++ b/README.md
@@ -213,8 +213,8 @@
A module name's **scope** is the smallest namespace containing it. Suppose a
source tree has `device/my` and `device/my/display` namespaces. If `libfoo`
-module is defined in `device/co/display/lib/Android.bp`, its namespace is
-`device/co/display`.
+module is defined in `device/my/display/lib/Android.bp`, its namespace is
+`device/my/display`.
The name uniqueness thus means that module's name is unique within its scope. In
other words, "//_scope_:_name_" is globally unique module reference, e.g,
diff --git a/android/apex.go b/android/apex.go
index 4618fe9..b9efe4e 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -54,6 +54,10 @@
// True if this module comes from an updatable apexBundle.
Updatable bool
+ // True if this module can use private platform APIs. Only non-updatable APEX can set this
+ // to true.
+ UsePlatformApis bool
+
// The list of SDK modules that the containing apexBundle depends on.
RequiredSdks SdkRefs
@@ -87,16 +91,31 @@
var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
+func (i ApexInfo) AddJSONData(d *map[string]interface{}) {
+ (*d)["Apex"] = map[string]interface{}{
+ "ApexVariationName": i.ApexVariationName,
+ "MinSdkVersion": i.MinSdkVersion,
+ "InApexModules": i.InApexModules,
+ "InApexVariants": i.InApexVariants,
+ "ForPrebuiltApex": i.ForPrebuiltApex,
+ }
+}
+
// mergedName gives the name of the alias variation that will be used when multiple apex variations
// of a module can be deduped into one variation. For example, if libfoo is included in both apex.a
// and apex.b, and if the two APEXes have the same min_sdk_version (say 29), then libfoo doesn't
// have to be built twice, but only once. In that case, the two apex variations apex.a and apex.b
-// are configured to have the same alias variation named apex29.
+// are configured to have the same alias variation named apex29. Whether platform APIs is allowed
+// or not also matters; if two APEXes don't have the same allowance, they get different names and
+// thus wouldn't be merged.
func (i ApexInfo) mergedName(ctx PathContext) string {
name := "apex" + strconv.Itoa(i.MinSdkVersion.FinalOrFutureInt())
for _, sdk := range i.RequiredSdks {
name += "_" + sdk.Name + "_" + sdk.Version
}
+ if i.UsePlatformApis {
+ name += "_private"
+ }
return name
}
@@ -527,6 +546,10 @@
merged[index].InApexModules = append(merged[index].InApexModules, apexInfo.InApexModules...)
merged[index].ApexContents = append(merged[index].ApexContents, apexInfo.ApexContents...)
merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
+ if merged[index].UsePlatformApis != apexInfo.UsePlatformApis {
+ panic(fmt.Errorf("variants having different UsePlatformApis can't be merged"))
+ }
+ merged[index].UsePlatformApis = apexInfo.UsePlatformApis
} else {
seen[mergedName] = len(merged)
apexInfo.ApexVariationName = mergedName
diff --git a/android/apex_test.go b/android/apex_test.go
index e112369..60a639b 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
{
name: "single",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"foo", "apex10000"},
@@ -45,11 +45,11 @@
{
name: "merge",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
+ {"apex10000_baz_1", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
wantAliases: [][2]string{
{"bar", "apex10000_baz_1"},
{"foo", "apex10000_baz_1"},
@@ -58,12 +58,12 @@
{
name: "don't merge version",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", uncheckedFinalApiLevel(30), false, false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex30", uncheckedFinalApiLevel(30), false, false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex30"},
@@ -73,11 +73,11 @@
{
name: "merge updatable",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, true, false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, false, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -87,12 +87,12 @@
{
name: "don't merge sdks",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000_baz_2", FutureApiLevel, false, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000_baz_1", FutureApiLevel, false, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000_baz_2"},
@@ -102,21 +102,36 @@
{
name: "don't merge when for prebuilt_apex",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, true, false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
// This one should not be merged in with the others because it is for
// a prebuilt_apex.
- {"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+ {"baz", FutureApiLevel, true, false, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
- {"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, false, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"baz", FutureApiLevel, true, false, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
{"foo", "apex10000"},
},
},
+ {
+ name: "don't merge different UsePlatformApis",
+ in: []ApexInfo{
+ {"foo", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000_private", FutureApiLevel, false, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex10000_private"},
+ {"foo", "apex10000"},
+ },
+ },
}
for _, tt := range tests {
diff --git a/android/module.go b/android/module.go
index f745a4a..07d82f1 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1190,6 +1190,10 @@
vintfFragmentsPaths Paths
}
+func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
+ (*d)["Android"] = map[string]interface{}{}
+}
+
func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {}
func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
diff --git a/android/sdk.go b/android/sdk.go
index 5c58612..e700031 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -375,6 +375,8 @@
// SdkMemberType returns the SdkMemberType that will be used to automatically add the child module
// to the sdk.
+ //
+ // Returning nil will prevent the module being added to the sdk.
SdkMemberType(child Module) SdkMemberType
// ExportMember determines whether a module added to the sdk through this tag will be exported
diff --git a/android/variable.go b/android/variable.go
index c766120..b6e168c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -101,6 +101,9 @@
Keep_symbols *bool
Keep_symbols_and_debug_frame *bool
}
+ Static_libs []string
+ Whole_static_libs []string
+ Shared_libs []string
}
// eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 067dcba..02ab89d 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -794,7 +794,7 @@
include $(BUILD_CTS_SUPPORT_PACKAGE)
`,
expected: `
-android_test {
+android_test_helper_app {
name: "FooTest",
defaults: ["cts_support_defaults"],
test_suites: ["cts"],
diff --git a/apex/apex.go b/apex/apex.go
index 7ffa6cc..baaf874 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -130,6 +130,10 @@
// symlinking to the system libs. Default is true.
Updatable *bool
+ // Whether this APEX can use platform APIs or not. Can be set to true only when `updatable:
+ // false`. Default is false.
+ Platform_apis *bool
+
// Whether this APEX is installable to one of the partitions like system, vendor, etc.
// Default: true.
Installable *bool
@@ -182,6 +186,12 @@
// used in tests.
Test_only_force_compression *bool
+ // Canonical name of this APEX bundle. Used to determine the path to the
+ // activated APEX on device (i.e. /apex/<apexVariationName>), and used for the
+ // apex mutator variations. For override_apex modules, this is the name of the
+ // overridden base module.
+ ApexVariationName string `blueprint:"mutated"`
+
IsCoverageVariant bool `blueprint:"mutated"`
// List of sanitizer names that this APEX is enabled for
@@ -824,6 +834,10 @@
var _ ApexInfoMutator = (*apexBundle)(nil)
+func (a *apexBundle) ApexVariationName() string {
+ return a.properties.ApexVariationName
+}
+
// ApexInfoMutator is responsible for collecting modules that need to have apex variants. They are
// identified by doing a graph walk starting from an apexBundle. Basically, all the (direct and
// indirect) dependencies are collected. But a few types of modules that shouldn't be included in
@@ -912,15 +926,16 @@
// This is the main part of this mutator. Mark the collected dependencies that they need to
// be built for this apexBundle.
- // Note that there are many different names.
- // ApexVariationName: this is the name of the apex variation
+ apexVariationName := proptools.StringDefault(a.properties.Apex_name, mctx.ModuleName()) // could be com.android.foo
+ a.properties.ApexVariationName = apexVariationName
apexInfo := android.ApexInfo{
- ApexVariationName: mctx.ModuleName(), // could be com.android.foo
+ ApexVariationName: apexVariationName,
MinSdkVersion: minSdkVersion,
RequiredSdks: a.RequiredSdks(),
Updatable: a.Updatable(),
- InApexVariants: []string{mctx.ModuleName()}, // could be com.android.foo
- InApexModules: []string{a.Name()}, // could be com.mycompany.android.foo
+ UsePlatformApis: a.UsePlatformApis(),
+ InApexVariants: []string{apexVariationName},
+ InApexModules: []string{a.Name()}, // could be com.mycompany.android.foo
ApexContents: []*android.ApexContents{apexContents},
}
mctx.WalkDeps(func(child, parent android.Module) bool {
@@ -933,6 +948,10 @@
}
type ApexInfoMutator interface {
+ // ApexVariationName returns the name of the APEX variation to use in the apex
+ // mutator etc. It is the same name as ApexInfo.ApexVariationName.
+ ApexVariationName() string
+
// ApexInfoMutator implementations must call BuildForApex(ApexInfo) on any modules that are
// depended upon by an apex and which require an apex specific variant.
ApexInfoMutator(android.TopDownMutatorContext)
@@ -1058,10 +1077,8 @@
}
// apexBundle itself is mutated so that it and its dependencies have the same apex variant.
- // TODO(jiyong): document the reason why the VNDK APEX is an exception here.
- unprefixedModuleName := android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName())
- if apexModuleTypeRequiresVariant(mctx.Module()) {
- apexBundleName := unprefixedModuleName
+ if ai, ok := mctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) {
+ apexBundleName := ai.ApexVariationName()
mctx.CreateVariations(apexBundleName)
if strings.HasPrefix(apexBundleName, "com.android.art") {
// Create an alias from the platform variant. This is done to make
@@ -1084,6 +1101,7 @@
// apex variant name. This name matches the name used to create the variations of modules for
// which apexModuleTypeRequiresVariant return true.
// TODO(b/191269918): Remove this workaround.
+ unprefixedModuleName := android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName())
mctx.SetDefaultDependencyVariation(&unprefixedModuleName)
mctx.CreateVariations(apexBundleName)
if strings.HasPrefix(apexBundleName, "com.android.art") {
@@ -1095,18 +1113,13 @@
// apexModuleTypeRequiresVariant determines whether the module supplied requires an apex specific
// variant.
-func apexModuleTypeRequiresVariant(module android.Module) bool {
+func apexModuleTypeRequiresVariant(module ApexInfoMutator) bool {
if a, ok := module.(*apexBundle); ok {
+ // TODO(jiyong): document the reason why the VNDK APEX is an exception here.
return !a.vndkApex
}
- // Match apex_set and prebuilt_apex. Would also match apexBundle but that is handled specially
- // above.
- if _, ok := module.(ApexInfoMutator); ok {
- return true
- }
-
- return false
+ return true
}
// See android.UpdateDirectlyInAnyApex
@@ -1321,6 +1334,10 @@
return proptools.BoolDefault(a.properties.Updatable, true)
}
+func (a *apexBundle) UsePlatformApis() bool {
+ return proptools.BoolDefault(a.properties.Platform_apis, false)
+}
+
// getCertString returns the name of the cert that should be used to sign this APEX. This is
// basically from the "certificate" property, but could be overridden by the device config.
func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
@@ -2374,6 +2391,9 @@
if String(a.properties.Min_sdk_version) == "" {
ctx.PropertyErrorf("updatable", "updatable APEXes should set min_sdk_version as well")
}
+ if a.UsePlatformApis() {
+ ctx.PropertyErrorf("updatable", "updatable APEXes can't use platform APIs")
+ }
a.checkJavaStableSdkVersion(ctx)
a.checkClasspathFragments(ctx)
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 792f7f3..b5b1d44 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -839,6 +839,7 @@
name: "myapex",
key: "myapex.key",
native_shared_libs: ["mylib", "mylib3"],
+ binaries: ["foo.rust"],
updatable: false,
}
@@ -887,6 +888,25 @@
stl: "none",
apex_available: [ "myapex" ],
}
+
+ rust_binary {
+ name: "foo.rust",
+ srcs: ["foo.rs"],
+ shared_libs: ["libfoo.shared_from_rust"],
+ prefer_rlib: true,
+ apex_available: ["myapex"],
+ }
+
+ cc_library_shared {
+ name: "libfoo.shared_from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["10", "11", "12"],
+ },
+ }
+
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
@@ -924,7 +944,90 @@
"lib64/mylib.so",
"lib64/mylib3.so",
"lib64/mylib4.so",
+ "bin/foo.rust",
+ "lib64/libc++.so", // by the implicit dependency from foo.rust
+ "lib64/liblog.so", // by the implicit dependency from foo.rust
})
+
+ // Ensure that stub dependency from a rust module is not included
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
+ // The rust module is linked to the stub cc library
+ rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
+ ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
+ ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
+}
+
+func TestApexCanUsePrivateApis(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ binaries: ["foo.rust"],
+ updatable: false,
+ platform_apis: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ cflags: ["-include mylib.h"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ }
+
+ rust_binary {
+ name: "foo.rust",
+ srcs: ["foo.rs"],
+ shared_libs: ["libfoo.shared_from_rust"],
+ prefer_rlib: true,
+ apex_available: ["myapex"],
+ }
+
+ cc_library_shared {
+ name: "libfoo.shared_from_rust",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["10", "11", "12"],
+ },
+ }
+ `)
+
+ apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ // Ensure that indirect stubs dep is not included
+ ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
+ ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
+
+ // Ensure that we are using non-stub variants of mylib2 and libfoo.shared_from_rust (because
+ // of the platform_apis: true)
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000_private").Rule("ld").Args["libFlags"]
+ ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
+ ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
+ rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000_private").Rule("rustc").Args["linkFlags"]
+ ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
+ ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
}
func TestApexWithStubsWithMinSdkVersion(t *testing.T) {
@@ -3972,13 +4075,13 @@
}
`)
- module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+ module := ctx.ModuleForTests("myapex", "android_common_com.android.myapex_image")
apexManifestRule := module.Rule("apexManifestRule")
ensureContains(t, apexManifestRule.Args["opt"], "-v name com.android.myapex")
apexRule := module.Rule("apexRule")
ensureContains(t, apexRule.Args["opt_flags"], "--do_not_check_keyname")
- apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ apexBundle := module.Module().(*apexBundle)
data := android.AndroidMkDataForTest(t, ctx, apexBundle)
name := apexBundle.BaseModuleName()
prefix := "TARGET_"
@@ -4521,6 +4624,59 @@
}
}
+func TestPrebuiltApexName(t *testing.T) {
+ testApex(t, `
+ prebuilt_apex {
+ name: "com.company.android.myapex",
+ apex_name: "com.android.myapex",
+ src: "company-myapex-arm.apex",
+ }
+ `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex")
+
+ testApex(t, `
+ apex_set {
+ name: "com.company.android.myapex",
+ apex_name: "com.android.myapex",
+ set: "company-myapex.apks",
+ }
+ `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex")
+}
+
+func TestPrebuiltApexNameWithPlatformBootclasspath(t *testing.T) {
+ _ = android.GroupFixturePreparers(
+ java.PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithApexBuildComponents,
+ android.FixtureWithRootAndroidBp(`
+ platform_bootclasspath {
+ name: "platform-bootclasspath",
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+
+ prebuilt_apex {
+ name: "com.company.android.art",
+ apex_name: "com.android.art",
+ src: "com.company.android.art-arm.apex",
+ exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ contents: ["core-oj"],
+ }
+
+ java_import {
+ name: "core-oj",
+ jars: ["prebuilt.jar"],
+ }
+ `),
+ ).RunTest(t)
+}
+
// These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the
// propagation of paths to dex implementation jars from the former to the latter.
func TestPrebuiltExportDexImplementationJars(t *testing.T) {
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 66bc9e0..4b1600e 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -22,6 +22,7 @@
"android/soong/android"
"android/soong/java"
+ "github.com/google/blueprint/proptools"
)
// Contains tests for bootclasspath_fragment logic from java/bootclasspath_fragment.go as the ART
@@ -216,9 +217,10 @@
`,
)
- checkSdkKindStubs := func(message string, info java.HiddenAPIInfo, kind android.SdkKind, expectedPaths ...string) {
+ checkAPIScopeStubs := func(message string, info java.HiddenAPIInfo, apiScope *java.HiddenAPIScope, expectedPaths ...string) {
t.Helper()
- android.AssertPathsRelativeToTopEquals(t, fmt.Sprintf("%s %s", message, kind), expectedPaths, info.TransitiveStubDexJarsByKind[kind])
+ paths := info.TransitiveStubDexJarsByScope.StubDexJarsForScope(apiScope)
+ android.AssertPathsRelativeToTopEquals(t, fmt.Sprintf("%s %s", message, apiScope), expectedPaths, paths)
}
// Check stub dex paths exported by art.
@@ -229,10 +231,10 @@
bazSystemStubs := "out/soong/.intermediates/baz.stubs.system/android_common/dex/baz.stubs.system.jar"
bazTestStubs := "out/soong/.intermediates/baz.stubs.test/android_common/dex/baz.stubs.test.jar"
- checkSdkKindStubs("art", artInfo, android.SdkPublic, bazPublicStubs)
- checkSdkKindStubs("art", artInfo, android.SdkSystem, bazSystemStubs)
- checkSdkKindStubs("art", artInfo, android.SdkTest, bazTestStubs)
- checkSdkKindStubs("art", artInfo, android.SdkCorePlatform)
+ checkAPIScopeStubs("art", artInfo, java.PublicHiddenAPIScope, bazPublicStubs)
+ checkAPIScopeStubs("art", artInfo, java.SystemHiddenAPIScope, bazSystemStubs)
+ checkAPIScopeStubs("art", artInfo, java.TestHiddenAPIScope, bazTestStubs)
+ checkAPIScopeStubs("art", artInfo, java.CorePlatformHiddenAPIScope)
// Check stub dex paths exported by other.
otherFragment := result.Module("other-bootclasspath-fragment", "android_common")
@@ -241,10 +243,10 @@
fooPublicStubs := "out/soong/.intermediates/foo.stubs/android_common/dex/foo.stubs.jar"
fooSystemStubs := "out/soong/.intermediates/foo.stubs.system/android_common/dex/foo.stubs.system.jar"
- checkSdkKindStubs("other", otherInfo, android.SdkPublic, bazPublicStubs, fooPublicStubs)
- checkSdkKindStubs("other", otherInfo, android.SdkSystem, bazSystemStubs, fooSystemStubs)
- checkSdkKindStubs("other", otherInfo, android.SdkTest, bazTestStubs, fooSystemStubs)
- checkSdkKindStubs("other", otherInfo, android.SdkCorePlatform)
+ checkAPIScopeStubs("other", otherInfo, java.PublicHiddenAPIScope, bazPublicStubs, fooPublicStubs)
+ checkAPIScopeStubs("other", otherInfo, java.SystemHiddenAPIScope, bazSystemStubs, fooSystemStubs)
+ checkAPIScopeStubs("other", otherInfo, java.TestHiddenAPIScope, bazTestStubs, fooSystemStubs)
+ checkAPIScopeStubs("other", otherInfo, java.CorePlatformHiddenAPIScope)
}
func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName, variantName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
@@ -718,4 +720,480 @@
checkFragmentExportedDexJar("bar", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/bar.jar")
}
+func getDexJarPath(result *android.TestResult, name string) string {
+ module := result.Module(name, "android_common")
+ return module.(java.UsesLibraryDependency).DexJarBuildPath().RelativeToTop().String()
+}
+
+// TestBootclasspathFragment_HiddenAPIList checks to make sure that the correct parameters are
+// passed to the hiddenapi list tool.
+func TestBootclasspathFragment_HiddenAPIList(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootclasspathFragment,
+ prepareForTestWithArtApex,
+ prepareForTestWithMyapex,
+ // Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
+ java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
+ // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+ // is disabled.
+ android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo", "quuz"),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ java_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ compile_dex: true,
+ }
+
+ java_sdk_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ compile_dex: true,
+ public: {enabled: true},
+ system: {enabled: true},
+ test: {enabled: true},
+ module_lib: {enabled: true},
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ // Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
+ contents: ["baz", "quuz"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "mybootclasspathfragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {enabled: true},
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: [
+ "foo",
+ "bar",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+ `)
+
+ java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+ "art-bootclasspath-fragment",
+ "bar",
+ "dex2oatd",
+ "foo",
+ })
+
+ fooStubs := getDexJarPath(result, "foo.stubs")
+ quuzPublicStubs := getDexJarPath(result, "quuz.stubs")
+ quuzSystemStubs := getDexJarPath(result, "quuz.stubs.system")
+ quuzTestStubs := getDexJarPath(result, "quuz.stubs.test")
+ quuzModuleLibStubs := getDexJarPath(result, "quuz.stubs.module_lib")
+
+ // Make sure that the fragment uses the quuz stub dex jars when generating the hidden API flags.
+ fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
+
+ rule := fragment.Rule("modularHiddenAPIStubFlagsFile")
+ command := rule.RuleParams.Command
+ android.AssertStringDoesContain(t, "check correct rule", command, "hiddenapi list")
+
+ // Make sure that the quuz stubs are available for resolving references from the implementation
+ // boot dex jars provided by this module.
+ android.AssertStringDoesContain(t, "quuz widest", command, "--dependency-stub-dex="+quuzModuleLibStubs)
+
+ // Make sure that the quuz stubs are available for resolving references from the different API
+ // stubs provided by this module.
+ android.AssertStringDoesContain(t, "public", command, "--public-stub-classpath="+quuzPublicStubs+":"+fooStubs)
+ android.AssertStringDoesContain(t, "system", command, "--system-stub-classpath="+quuzSystemStubs+":"+fooStubs)
+ android.AssertStringDoesContain(t, "test", command, "--test-stub-classpath="+quuzTestStubs+":"+fooStubs)
+}
+
+// TestBootclasspathFragment_AndroidNonUpdatable checks to make sure that setting
+// additional_stubs: ["android-non-updatable"] causes the source android-non-updatable modules to be
+// added to the hiddenapi list tool.
+func TestBootclasspathFragment_AndroidNonUpdatable(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootclasspathFragment,
+ prepareForTestWithArtApex,
+ prepareForTestWithMyapex,
+ // Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "myapex:foo", "myapex:bar"),
+ // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+ // is disabled.
+ android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo", "android-non-updatable"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "android-non-updatable",
+ srcs: ["b.java"],
+ compile_dex: true,
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+ test: {
+ enabled: true,
+ },
+ module_lib: {
+ enabled: true,
+ },
+ }
+
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ java_libs: [
+ "baz",
+ "quuz",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ java_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ compile_dex: true,
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ compile_dex: true,
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ // Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
+ contents: ["baz", "quuz"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "mybootclasspathfragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {enabled: true},
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: [
+ "foo",
+ "bar",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ additional_stubs: ["android-non-updatable"],
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+ `)
+
+ java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+ "android-non-updatable.stubs",
+ "android-non-updatable.stubs.module_lib",
+ "android-non-updatable.stubs.system",
+ "android-non-updatable.stubs.test",
+ "art-bootclasspath-fragment",
+ "bar",
+ "dex2oatd",
+ "foo",
+ })
+
+ nonUpdatablePublicStubs := getDexJarPath(result, "android-non-updatable.stubs")
+ nonUpdatableSystemStubs := getDexJarPath(result, "android-non-updatable.stubs.system")
+ nonUpdatableTestStubs := getDexJarPath(result, "android-non-updatable.stubs.test")
+ nonUpdatableModuleLibStubs := getDexJarPath(result, "android-non-updatable.stubs.module_lib")
+
+ // Make sure that the fragment uses the android-non-updatable modules when generating the hidden
+ // API flags.
+ fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
+
+ rule := fragment.Rule("modularHiddenAPIStubFlagsFile")
+ command := rule.RuleParams.Command
+ android.AssertStringDoesContain(t, "check correct rule", command, "hiddenapi list")
+
+ // Make sure that the module_lib non-updatable stubs are available for resolving references from
+ // the implementation boot dex jars provided by this module.
+ android.AssertStringDoesContain(t, "android-non-updatable widest", command, "--dependency-stub-dex="+nonUpdatableModuleLibStubs)
+
+ // Make sure that the appropriate non-updatable stubs are available for resolving references from
+ // the different API stubs provided by this module.
+ android.AssertStringDoesContain(t, "public", command, "--public-stub-classpath="+nonUpdatablePublicStubs)
+ android.AssertStringDoesContain(t, "system", command, "--system-stub-classpath="+nonUpdatableSystemStubs)
+ android.AssertStringDoesContain(t, "test", command, "--test-stub-classpath="+nonUpdatableTestStubs)
+}
+
+// TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks checks to make sure that
+// setting additional_stubs: ["android-non-updatable"] causes the prebuilt android-non-updatable
+// modules to be added to the hiddenapi list tool.
+func TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootclasspathFragment,
+ java.PrepareForTestWithJavaDefaultModules,
+ prepareForTestWithArtApex,
+ prepareForTestWithMyapex,
+ // Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
+ java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "myapex:foo", "myapex:bar"),
+ // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+ // is disabled.
+ android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
+ }),
+
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithPrebuiltApis(map[string][]string{
+ "current": {"android-non-updatable"},
+ "30": {"foo"},
+ }),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "com.android.art",
+ key: "com.android.art.key",
+ bootclasspath_fragments: ["art-bootclasspath-fragment"],
+ java_libs: [
+ "baz",
+ "quuz",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "com.android.art.key",
+ public_key: "com.android.art.avbpubkey",
+ private_key: "com.android.art.pem",
+ }
+
+ java_library {
+ name: "baz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ compile_dex: true,
+ }
+
+ java_library {
+ name: "quuz",
+ apex_available: [
+ "com.android.art",
+ ],
+ srcs: ["b.java"],
+ compile_dex: true,
+ }
+
+ bootclasspath_fragment {
+ name: "art-bootclasspath-fragment",
+ image_name: "art",
+ // Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
+ contents: ["baz", "quuz"],
+ apex_available: [
+ "com.android.art",
+ ],
+ }
+
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "mybootclasspathfragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {enabled: true},
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: [
+ "foo",
+ "bar",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ additional_stubs: ["android-non-updatable"],
+ fragments: [
+ {
+ apex: "com.android.art",
+ module: "art-bootclasspath-fragment",
+ },
+ ],
+ }
+ `)
+
+ java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+ "art-bootclasspath-fragment",
+ "bar",
+ "dex2oatd",
+ "foo",
+ "prebuilt_sdk_module-lib_current_android-non-updatable",
+ "prebuilt_sdk_public_current_android-non-updatable",
+ "prebuilt_sdk_system_current_android-non-updatable",
+ "prebuilt_sdk_test_current_android-non-updatable",
+ })
+
+ nonUpdatablePublicStubs := getDexJarPath(result, "sdk_public_current_android-non-updatable")
+ nonUpdatableSystemStubs := getDexJarPath(result, "sdk_system_current_android-non-updatable")
+ nonUpdatableTestStubs := getDexJarPath(result, "sdk_test_current_android-non-updatable")
+ nonUpdatableModuleLibStubs := getDexJarPath(result, "sdk_module-lib_current_android-non-updatable")
+
+ // Make sure that the fragment uses the android-non-updatable modules when generating the hidden
+ // API flags.
+ fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
+
+ rule := fragment.Rule("modularHiddenAPIStubFlagsFile")
+ command := rule.RuleParams.Command
+ android.AssertStringDoesContain(t, "check correct rule", command, "hiddenapi list")
+
+ // Make sure that the module_lib non-updatable stubs are available for resolving references from
+ // the implementation boot dex jars provided by this module.
+ android.AssertStringDoesContain(t, "android-non-updatable widest", command, "--dependency-stub-dex="+nonUpdatableModuleLibStubs)
+
+ // Make sure that the appropriate non-updatable stubs are available for resolving references from
+ // the different API stubs provided by this module.
+ android.AssertStringDoesContain(t, "public", command, "--public-stub-classpath="+nonUpdatablePublicStubs)
+ android.AssertStringDoesContain(t, "system", command, "--system-stub-classpath="+nonUpdatableSystemStubs)
+ android.AssertStringDoesContain(t, "test", command, "--test-stub-classpath="+nonUpdatableTestStubs)
+}
+
// TODO(b/177892522) - add test for host apex.
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index ea06d45..1bb0fb5 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -24,7 +24,6 @@
"android/soong/java"
"github.com/google/blueprint"
-
"github.com/google/blueprint/proptools"
)
@@ -76,6 +75,10 @@
type PrebuiltCommonProperties struct {
SelectedApexProperties
+ // Canonical name of this APEX. Used to determine the path to the activated APEX on
+ // device (/apex/<apex_name>). If unspecified, follows the name property.
+ Apex_name *string
+
ForceDisable bool `blueprint:"mutated"`
// whether the extracted apex file is installable.
@@ -110,6 +113,10 @@
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
}
+func (p *prebuiltCommon) ApexVariationName() string {
+ return proptools.StringDefault(p.prebuiltCommonProperties.Apex_name, p.ModuleBase.BaseModuleName())
+}
+
func (p *prebuiltCommon) Prebuilt() *android.Prebuilt {
return &p.prebuilt
}
@@ -369,6 +376,12 @@
}
}
+ // Ignore any modules that do not implement ApexModule as they cannot have an APEX specific
+ // variant.
+ if _, ok := child.(android.ApexModule); !ok {
+ return false
+ }
+
// Strip off the prebuilt_ prefix if present before storing content to ensure consistent
// behavior whether there is a corresponding source module present or not.
depName = android.RemoveOptionalPrebuiltPrefix(depName)
@@ -390,11 +403,11 @@
})
// Create an ApexInfo for the prebuilt_apex.
- apexVariationName := android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName())
+ apexVariationName := p.ApexVariationName()
apexInfo := android.ApexInfo{
ApexVariationName: apexVariationName,
InApexVariants: []string{apexVariationName},
- InApexModules: []string{apexVariationName},
+ InApexModules: []string{p.ModuleBase.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix.
ApexContents: []*android.ApexContents{apexContents},
ForPrebuiltApex: true,
}
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index fae6101..9640024 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -319,7 +319,7 @@
var defStr string
switch mod.Type {
case "cts_support_package":
- mod.Type = "android_test"
+ mod.Type = "android_test_helper_app"
defStr = "cts_support_defaults"
case "cts_package":
mod.Type = "android_test"
@@ -622,12 +622,20 @@
func rewriteAndroidTest(f *Fixer) error {
for _, def := range f.tree.Defs {
mod, ok := def.(*parser.Module)
- if !(ok && mod.Type == "android_test") {
+ if !ok {
+ // The definition is not a module.
+ continue
+ }
+ if mod.Type != "android_test" && mod.Type != "android_test_helper_app" {
+ // The module is not an android_test or android_test_helper_app.
continue
}
// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
// 'local_module_path'. For the android_test module, it should be $(TARGET_OUT_DATA_APPS),
// that is, `local_module_path: { var: "TARGET_OUT_DATA_APPS"}`
+ // 1. if the `key: val` pair matches, (key is `local_module_path`,
+ // and val is `{ var: "TARGET_OUT_DATA_APPS"}`), this property is removed;
+ // 2. o/w, an error msg is thrown.
const local_module_path = "local_module_path"
if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok {
removeProperty(mod, local_module_path)
@@ -637,7 +645,7 @@
continue
}
return indicateAttributeError(mod, "filename",
- "Only LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) is allowed for the android_test")
+ "Only LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) is allowed for the %s", mod.Type)
}
}
return nil
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 61dfe1a..ebfeb22 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -636,7 +636,7 @@
}
`,
out: `
- android_test {
+ android_test_helper_app {
name: "foo",
defaults: ["cts_support_defaults"],
}
diff --git a/cc/binary.go b/cc/binary.go
index 3aa3fdf..48f70d9 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -146,16 +146,17 @@
// modules common to most binaries, such as bionic libraries.
func (binary *binaryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps = binary.baseLinker.linkerDeps(ctx, deps)
- if ctx.toolchain().Bionic() {
- if !Bool(binary.baseLinker.Properties.Nocrt) {
- if binary.static() {
- deps.CrtBegin = []string{"crtbegin_static"}
- } else {
- deps.CrtBegin = []string{"crtbegin_dynamic"}
- }
- deps.CrtEnd = []string{"crtend_android"}
+ if !Bool(binary.baseLinker.Properties.Nocrt) {
+ if binary.static() {
+ deps.CrtBegin = ctx.toolchain().CrtBeginStaticBinary()
+ deps.CrtEnd = ctx.toolchain().CrtEndStaticBinary()
+ } else {
+ deps.CrtBegin = ctx.toolchain().CrtBeginSharedBinary()
+ deps.CrtEnd = ctx.toolchain().CrtEndSharedBinary()
}
+ }
+ if ctx.toolchain().Bionic() {
if binary.static() {
if ctx.selectedStl() == "libc++_static" {
deps.StaticLibs = append(deps.StaticLibs, "libm", "libc")
@@ -169,16 +170,8 @@
deps.LateStaticLibs = append(groupLibs, deps.LateStaticLibs...)
}
- // Embed the linker into host bionic binaries. This is needed to support host bionic,
- // as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be
- // either an absolute path, or relative from CWD. To work around this, we extract
- // the load sections from the runtime linker ELF binary and embed them into each host
- // bionic binary, omitting the PT_INTERP declaration. The kernel will treat it as a static
- // binary, and then we use a special entry point to fix up the arguments passed by
- // the kernel before jumping to the embedded linker.
if ctx.Os() == android.LinuxBionic && !binary.static() {
deps.DynamicLinker = "linker"
- deps.CrtBegin = append(deps.CrtBegin, "host_bionic_linker_script")
}
}
diff --git a/cc/cc.go b/cc/cc.go
index 0c9f945..0aa1014 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -571,7 +571,8 @@
sharedLibs []string
// Note nil and [] are semantically distinct. [] prevents linking against the defaults (usually
// libc, libm, etc.)
- systemSharedLibs []string
+ systemSharedLibs []string
+ defaultSharedLibs []string
}
// installer is the interface for an installer helper object. This helper is responsible for
@@ -831,6 +832,46 @@
hideApexVariantFromMake bool
}
+func (c *Module) AddJSONData(d *map[string]interface{}) {
+ c.AndroidModuleBase().AddJSONData(d)
+ (*d)["Cc"] = map[string]interface{}{
+ "SdkVersion": c.SdkVersion(),
+ "MinSdkVersion": c.MinSdkVersion(),
+ "VndkVersion": c.VndkVersion(),
+ "ProductSpecific": c.ProductSpecific(),
+ "SocSpecific": c.SocSpecific(),
+ "DeviceSpecific": c.DeviceSpecific(),
+ "InProduct": c.InProduct(),
+ "InVendor": c.InVendor(),
+ "InRamdisk": c.InRamdisk(),
+ "InVendorRamdisk": c.InVendorRamdisk(),
+ "InRecovery": c.InRecovery(),
+ "VendorAvailable": c.VendorAvailable(),
+ "ProductAvailable": c.ProductAvailable(),
+ "RamdiskAvailable": c.RamdiskAvailable(),
+ "VendorRamdiskAvailable": c.VendorRamdiskAvailable(),
+ "RecoveryAvailable": c.RecoveryAvailable(),
+ "OdmAvailable": c.OdmAvailable(),
+ "InstallInData": c.InstallInData(),
+ "InstallInRamdisk": c.InstallInRamdisk(),
+ "InstallInSanitizerDir": c.InstallInSanitizerDir(),
+ "InstallInVendorRamdisk": c.InstallInVendorRamdisk(),
+ "InstallInRecovery": c.InstallInRecovery(),
+ "InstallInRoot": c.InstallInRoot(),
+ "IsVndk": c.IsVndk(),
+ "IsVndkExt": c.IsVndkExt(),
+ "IsVndkPrivate": c.IsVndkPrivate(),
+ "IsVndkSp": c.IsVndkSp(),
+ "IsLlndk": c.IsLlndk(),
+ "IsLlndkPublic": c.IsLlndkPublic(),
+ "IsSnapshotLibrary": c.IsSnapshotLibrary(),
+ "IsSnapshotPrebuilt": c.IsSnapshotPrebuilt(),
+ "IsVendorPublicLibrary": c.IsVendorPublicLibrary(),
+ "ApexSdkVersion": c.apexSdkVersion,
+ "TestFor": c.TestFor(),
+ }
+}
+
func (c *Module) SetPreventInstall() {
c.Properties.PreventInstall = true
}
@@ -1259,7 +1300,7 @@
return name
}
-func (c *Module) bootstrap() bool {
+func (c *Module) Bootstrap() bool {
return Bool(c.Properties.Bootstrap)
}
@@ -1504,7 +1545,7 @@
}
func (ctx *moduleContextImpl) bootstrap() bool {
- return ctx.mod.bootstrap()
+ return ctx.mod.Bootstrap()
}
func (ctx *moduleContextImpl) nativeCoverage() bool {
@@ -2646,66 +2687,8 @@
return
}
- sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
- sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryStubsProvider).(SharedLibraryStubsInfo)
-
- if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
- useStubs := false
-
- if lib := moduleLibraryInterface(dep); lib.buildStubs() && c.UseVndk() { // LLNDK
- if !apexInfo.IsForPlatform() {
- // For platform libraries, use current version of LLNDK
- // If this is for use_vendor apex we will apply the same rules
- // of apex sdk enforcement below to choose right version.
- useStubs = true
- }
- } else if apexInfo.IsForPlatform() {
- // If not building for APEX, use stubs only when it is from
- // an APEX (and not from platform)
- // However, for host, ramdisk, vendor_ramdisk, recovery or bootstrap modules,
- // always link to non-stub variant
- useStubs = dep.(android.ApexModule).NotInPlatform() && !c.bootstrap()
- if useStubs {
- // Another exception: if this module is a test for an APEX, then
- // it is linked with the non-stub variant of a module in the APEX
- // as if this is part of the APEX.
- testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
- for _, apexContents := range testFor.ApexContents {
- if apexContents.DirectlyInApex(depName) {
- useStubs = false
- break
- }
- }
- }
- if useStubs {
- // Yet another exception: If this module and the dependency are
- // available to the same APEXes then skip stubs between their
- // platform variants. This complements the test_for case above,
- // which avoids the stubs on a direct APEX library dependency, by
- // avoiding stubs for indirect test dependencies as well.
- //
- // TODO(b/183882457): This doesn't work if the two libraries have
- // only partially overlapping apex_available. For that test_for
- // modules would need to be split into APEX variants and resolved
- // separately for each APEX they have access to.
- if android.AvailableToSameApexes(c, dep.(android.ApexModule)) {
- useStubs = false
- }
- }
- } else {
- // If building for APEX, use stubs when the parent is in any APEX that
- // the child is not in.
- useStubs = !android.DirectlyInAllApexes(apexInfo, depName)
- }
-
- // when to use (unspecified) stubs, use the latest one.
- if useStubs {
- stubs := sharedLibraryStubsInfo.SharedStubLibraries
- toUse := stubs[len(stubs)-1]
- sharedLibraryInfo = toUse.SharedLibraryInfo
- depExporterInfo = toUse.FlagExporterInfo
- }
- }
+ sharedLibraryInfo, returnedDepExporterInfo := ChooseStubOrImpl(ctx, dep)
+ depExporterInfo = returnedDepExporterInfo
// Stubs lib doesn't link to the shared lib dependencies. Don't set
// linkFile, depFile, and ptr.
@@ -2918,6 +2901,100 @@
return depPaths
}
+// ChooseStubOrImpl determines whether a given dependency should be redirected to the stub variant
+// of the dependency or not, and returns the SharedLibraryInfo and FlagExporterInfo for the right
+// dependency. The stub variant is selected when the dependency crosses a boundary where each side
+// has different level of updatability. For example, if a library foo in an APEX depends on a
+// library bar which provides stable interface and exists in the platform, foo uses the stub variant
+// of bar. If bar doesn't provide a stable interface (i.e. buildStubs() == false) or is in the
+// same APEX as foo, the non-stub variant of bar is used.
+func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibraryInfo, FlagExporterInfo) {
+ depName := ctx.OtherModuleName(dep)
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ libDepTag, ok := depTag.(libraryDependencyTag)
+ if !ok || !libDepTag.shared() {
+ panic(fmt.Errorf("Unexpected dependency tag: %T", depTag))
+ }
+
+ thisModule, ok := ctx.Module().(android.ApexModule)
+ if !ok {
+ panic(fmt.Errorf("Not an APEX module: %q", ctx.ModuleName()))
+ }
+
+ useVndk := false
+ bootstrap := false
+ if linkable, ok := ctx.Module().(LinkableInterface); !ok {
+ panic(fmt.Errorf("Not a Linkable module: %q", ctx.ModuleName()))
+ } else {
+ useVndk = linkable.UseVndk()
+ bootstrap = linkable.Bootstrap()
+ }
+
+ sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
+ depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+ sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryStubsProvider).(SharedLibraryStubsInfo)
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+
+ if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
+ useStubs := false
+
+ if lib := moduleLibraryInterface(dep); lib.buildStubs() && useVndk { // LLNDK
+ if !apexInfo.IsForPlatform() {
+ // For platform libraries, use current version of LLNDK
+ // If this is for use_vendor apex we will apply the same rules
+ // of apex sdk enforcement below to choose right version.
+ useStubs = true
+ }
+ } else if apexInfo.IsForPlatform() || apexInfo.UsePlatformApis {
+ // If not building for APEX or the containing APEX allows the use of
+ // platform APIs, use stubs only when it is from an APEX (and not from
+ // platform) However, for host, ramdisk, vendor_ramdisk, recovery or
+ // bootstrap modules, always link to non-stub variant
+ useStubs = dep.(android.ApexModule).NotInPlatform() && !bootstrap
+ if useStubs {
+ // Another exception: if this module is a test for an APEX, then
+ // it is linked with the non-stub variant of a module in the APEX
+ // as if this is part of the APEX.
+ testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
+ for _, apexContents := range testFor.ApexContents {
+ if apexContents.DirectlyInApex(depName) {
+ useStubs = false
+ break
+ }
+ }
+ }
+ if useStubs {
+ // Yet another exception: If this module and the dependency are
+ // available to the same APEXes then skip stubs between their
+ // platform variants. This complements the test_for case above,
+ // which avoids the stubs on a direct APEX library dependency, by
+ // avoiding stubs for indirect test dependencies as well.
+ //
+ // TODO(b/183882457): This doesn't work if the two libraries have
+ // only partially overlapping apex_available. For that test_for
+ // modules would need to be split into APEX variants and resolved
+ // separately for each APEX they have access to.
+ if android.AvailableToSameApexes(thisModule, dep.(android.ApexModule)) {
+ useStubs = false
+ }
+ }
+ } else {
+ // If building for APEX, use stubs when the parent is in any APEX that
+ // the child is not in.
+ useStubs = !android.DirectlyInAllApexes(apexInfo, depName)
+ }
+
+ // when to use (unspecified) stubs, use the latest one.
+ if useStubs {
+ stubs := sharedLibraryStubsInfo.SharedStubLibraries
+ toUse := stubs[len(stubs)-1]
+ sharedLibraryInfo = toUse.SharedLibraryInfo
+ depExporterInfo = toUse.FlagExporterInfo
+ }
+ }
+ return sharedLibraryInfo, depExporterInfo
+}
+
// orderStaticModuleDeps rearranges the order of the static library dependencies of the module
// to match the topological order of the dependency tree, including any static analogues of
// direct shared libraries. It returns the ordered static dependencies, and an android.DepSet
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 2d0d78b..0a74e58 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3662,305 +3662,6 @@
android.AssertStringDoesContain(t, "min sdk version", cFlags, "-target aarch64-linux-android29")
}
-type MemtagNoteType int
-
-const (
- None MemtagNoteType = iota + 1
- Sync
- Async
-)
-
-func (t MemtagNoteType) str() string {
- switch t {
- case None:
- return "none"
- case Sync:
- return "sync"
- case Async:
- return "async"
- default:
- panic("invalid note type")
- }
-}
-
-func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNoteType) {
- note_async := "note_memtag_heap_async"
- note_sync := "note_memtag_heap_sync"
-
- found := None
- implicits := m.Rule("ld").Implicits
- for _, lib := range implicits {
- if strings.Contains(lib.Rel(), note_async) {
- found = Async
- break
- } else if strings.Contains(lib.Rel(), note_sync) {
- found = Sync
- break
- }
- }
-
- if found != expected {
- t.Errorf("Wrong Memtag note in target %q: found %q, expected %q", m.Module().(*Module).Name(), found.str(), expected.str())
- }
-}
-
-var prepareForTestWithMemtagHeap = android.GroupFixturePreparers(
- android.FixtureModifyMockFS(func(fs android.MockFS) {
- templateBp := `
- cc_test {
- name: "%[1]s_test",
- gtest: false,
- }
-
- cc_test {
- name: "%[1]s_test_false",
- gtest: false,
- sanitize: { memtag_heap: false },
- }
-
- cc_test {
- name: "%[1]s_test_true",
- gtest: false,
- sanitize: { memtag_heap: true },
- }
-
- cc_test {
- name: "%[1]s_test_true_nodiag",
- gtest: false,
- sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
- }
-
- cc_test {
- name: "%[1]s_test_true_diag",
- gtest: false,
- sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
- }
-
- cc_binary {
- name: "%[1]s_binary",
- }
-
- cc_binary {
- name: "%[1]s_binary_false",
- sanitize: { memtag_heap: false },
- }
-
- cc_binary {
- name: "%[1]s_binary_true",
- sanitize: { memtag_heap: true },
- }
-
- cc_binary {
- name: "%[1]s_binary_true_nodiag",
- sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
- }
-
- cc_binary {
- name: "%[1]s_binary_true_diag",
- sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
- }
- `
- subdirDefaultBp := fmt.Sprintf(templateBp, "default")
- subdirExcludeBp := fmt.Sprintf(templateBp, "exclude")
- subdirSyncBp := fmt.Sprintf(templateBp, "sync")
- subdirAsyncBp := fmt.Sprintf(templateBp, "async")
-
- fs.Merge(android.MockFS{
- "subdir_default/Android.bp": []byte(subdirDefaultBp),
- "subdir_exclude/Android.bp": []byte(subdirExcludeBp),
- "subdir_sync/Android.bp": []byte(subdirSyncBp),
- "subdir_async/Android.bp": []byte(subdirAsyncBp),
- })
- }),
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.MemtagHeapExcludePaths = []string{"subdir_exclude"}
- // "subdir_exclude" is covered by both include and exclude paths. Exclude wins.
- variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_exclude"}
- variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_exclude"}
- }),
-)
-
-func TestSanitizeMemtagHeap(t *testing.T) {
- variant := "android_arm64_armv8-a"
-
- result := android.GroupFixturePreparers(
- prepareForCcTest,
- prepareForTestWithMemtagHeap,
- ).RunTest(t)
- ctx := result.TestContext
-
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_diag", variant), Sync)
-}
-
-func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) {
- variant := "android_arm64_armv8-a"
-
- result := android.GroupFixturePreparers(
- prepareForCcTest,
- prepareForTestWithMemtagHeap,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.SanitizeDevice = []string{"memtag_heap"}
- }),
- ).RunTest(t)
- ctx := result.TestContext
-
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_diag", variant), Sync)
-}
-
-func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) {
- variant := "android_arm64_armv8-a"
-
- result := android.GroupFixturePreparers(
- prepareForCcTest,
- prepareForTestWithMemtagHeap,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.SanitizeDevice = []string{"memtag_heap"}
- variables.SanitizeDeviceDiag = []string{"memtag_heap"}
- }),
- ).RunTest(t)
- ctx := result.TestContext
-
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_diag", variant), Sync)
-
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_false", variant), None)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true", variant), Sync)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_nodiag", variant), Async)
- checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_diag", variant), Sync)
-}
-
func TestIncludeDirsExporting(t *testing.T) {
// Trim spaces from the beginning, end and immediately after any newline characters. Leaves
@@ -4345,12 +4046,12 @@
"${config.ArmToolchainClangCflags}",
"${config.ArmClangArmv7ANeonCflags}",
"${config.ArmClangGenericCflags}",
- "export_include_dirs",
- "linux_export_include_dirs",
- "android_export_include_dirs",
- "arm_export_include_dirs",
- "lib32_export_include_dirs",
"android_arm_export_include_dirs",
+ "lib32_export_include_dirs",
+ "arm_export_include_dirs",
+ "android_export_include_dirs",
+ "linux_export_include_dirs",
+ "export_include_dirs",
"android_arm_local_include_dirs",
"lib32_local_include_dirs",
"arm_local_include_dirs",
diff --git a/cc/compiler.go b/cc/compiler.go
index 78a5a5d..69ead30 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -92,7 +92,7 @@
// list of generated headers to add to the include path. These are the names
// of genrule modules.
- Generated_headers []string `android:"arch_variant"`
+ Generated_headers []string `android:"arch_variant,variant_prepend"`
// pass -frtti instead of -fno-rtti
Rtti *bool
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index e4a8b62..c1d4f17 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -17,6 +17,8 @@
"toolchain.go",
"vndk.go",
+ "bionic.go",
+
"arm_device.go",
"arm64_device.go",
"arm64_fuchsia_device.go",
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 864fba1..af6361b 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -149,6 +149,7 @@
)
type toolchainArm64 struct {
+ toolchainBionic
toolchain64Bit
ldflags string
diff --git a/cc/config/arm64_fuchsia_device.go b/cc/config/arm64_fuchsia_device.go
index 02c0c14..a6b5e8c 100644
--- a/cc/config/arm64_fuchsia_device.go
+++ b/cc/config/arm64_fuchsia_device.go
@@ -82,10 +82,6 @@
return "--target=arm64-fuchsia --sysroot=" + fuchsiaArm64SysRoot + " -I" + fuchsiaArm64SysRoot + "/include"
}
-func (t *toolchainFuchsiaArm64) Bionic() bool {
- return false
-}
-
func (t *toolchainFuchsiaArm64) ToolchainClangCflags() string {
return "-march=armv8-a"
}
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 59c52d1..83bd799 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -45,6 +45,16 @@
"-Wl,--hash-style=gnu",
"-Wl,--no-undefined-version",
})
+
+ // Embed the linker into host bionic binaries. This is needed to support host bionic,
+ // as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be
+ // either an absolute path, or relative from CWD. To work around this, we extract
+ // the load sections from the runtime linker ELF binary and embed them into each host
+ // bionic binary, omitting the PT_INTERP declaration. The kernel will treat it as a static
+ // binary, and then we use a special entry point to fix up the arguments passed by
+ // the kernel before jumping to the embedded linker.
+ linuxArm64CrtBeginSharedBinary = append(android.CopyOf(bionicCrtBeginSharedBinary),
+ "host_bionic_linker_script")
)
func init() {
@@ -68,6 +78,10 @@
return "${config.Arm64ClangCflags} ${config.LinuxBionicArm64Cflags}"
}
+func (toolchainLinuxArm64) CrtBeginSharedBinary() []string {
+ return linuxArm64CrtBeginSharedBinary
+}
+
func linuxArm64ToolchainFactory(arch android.Arch) Toolchain {
archVariant := "armv8-a" // for host, default to armv8-a
toolchainClangCflags := []string{arm64ClangArchVariantCflagsVar[archVariant]}
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 439084e..3c27730 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -237,6 +237,7 @@
)
type toolchainArm struct {
+ toolchainBionic
toolchain32Bit
ldflags string
lldflags string
diff --git a/cc/config/bionic.go b/cc/config/bionic.go
new file mode 100644
index 0000000..e87f571
--- /dev/null
+++ b/cc/config/bionic.go
@@ -0,0 +1,37 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+type toolchainBionic struct {
+}
+
+var (
+ bionicDefaultSharedLibraries = []string{"libc", "libm", "libdl"}
+
+ bionicCrtBeginStaticBinary, bionicCrtEndStaticBinary = []string{"crtbegin_static"}, []string{"crtend_android"}
+ bionicCrtBeginSharedBinary, bionicCrtEndSharedBinary = []string{"crtbegin_dynamic"}, []string{"crtend_android"}
+ bionicCrtBeginSharedLibrary, bionicCrtEndSharedLibrary = []string{"crtbegin_so"}, []string{"crtend_so"}
+)
+
+func (toolchainBionic) Bionic() bool { return true }
+
+func (toolchainBionic) DefaultSharedLibraries() []string { return bionicDefaultSharedLibraries }
+
+func (toolchainBionic) CrtBeginStaticBinary() []string { return bionicCrtBeginStaticBinary }
+func (toolchainBionic) CrtBeginSharedBinary() []string { return bionicCrtBeginSharedBinary }
+func (toolchainBionic) CrtBeginSharedLibrary() []string { return bionicCrtBeginSharedLibrary }
+func (toolchainBionic) CrtEndStaticBinary() []string { return bionicCrtEndStaticBinary }
+func (toolchainBionic) CrtEndSharedBinary() []string { return bionicCrtEndSharedBinary }
+func (toolchainBionic) CrtEndSharedLibrary() []string { return bionicCrtEndSharedLibrary }
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index fce28c1..ab09751 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -106,6 +106,17 @@
AvailableLibraries() []string
+ CrtBeginStaticBinary() []string
+ CrtBeginSharedBinary() []string
+ CrtBeginSharedLibrary() []string
+ CrtEndStaticBinary() []string
+ CrtEndSharedBinary() []string
+ CrtEndSharedLibrary() []string
+
+ // DefaultSharedLibraries returns the list of shared libraries that will be added to all
+ // targets unless they explicitly specify system_shared_libs.
+ DefaultSharedLibraries() []string
+
Bionic() bool
}
@@ -165,11 +176,22 @@
}
func (toolchainBase) AvailableLibraries() []string {
- return []string{}
+ return nil
+}
+
+func (toolchainBase) CrtBeginStaticBinary() []string { return nil }
+func (toolchainBase) CrtBeginSharedBinary() []string { return nil }
+func (toolchainBase) CrtBeginSharedLibrary() []string { return nil }
+func (toolchainBase) CrtEndStaticBinary() []string { return nil }
+func (toolchainBase) CrtEndSharedBinary() []string { return nil }
+func (toolchainBase) CrtEndSharedLibrary() []string { return nil }
+
+func (toolchainBase) DefaultSharedLibraries() []string {
+ return nil
}
func (toolchainBase) Bionic() bool {
- return true
+ return false
}
func (t toolchainBase) ToolPath() string {
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 1e25a3b..54dc6d5 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -123,6 +123,7 @@
}
type toolchainX86_64 struct {
+ toolchainBionic
toolchain64Bit
toolchainClangCflags string
}
diff --git a/cc/config/x86_64_fuchsia_device.go b/cc/config/x86_64_fuchsia_device.go
index 0f2013b..d6837c8 100644
--- a/cc/config/x86_64_fuchsia_device.go
+++ b/cc/config/x86_64_fuchsia_device.go
@@ -83,10 +83,6 @@
return "--target=x86_64-fuchsia --sysroot=" + fuchsiaSysRoot + " -I" + fuchsiaSysRoot + "/include"
}
-func (t *toolchainFuchsiaX8664) Bionic() bool {
- return false
-}
-
func (t *toolchainFuchsiaX8664) YasmFlags() string {
return "-f elf64 -m amd64"
}
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index b0344af..4e3e2a6 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -241,10 +241,6 @@
return darwinAvailableLibraries
}
-func (t *toolchainDarwin) Bionic() bool {
- return false
-}
-
func (t *toolchainDarwin) ToolPath() string {
return "${config.MacToolPath}"
}
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index fe83098..1507d98 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -134,6 +134,7 @@
}
type toolchainX86 struct {
+ toolchainBionic
toolchain32Bit
toolchainClangCflags string
}
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index fa625e3..e7e5f2d 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -63,6 +63,16 @@
})
linuxBionicLldflags = ClangFilterUnknownLldflags(linuxBionicLdflags)
+
+ // Embed the linker into host bionic binaries. This is needed to support host bionic,
+ // as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be
+ // either an absolute path, or relative from CWD. To work around this, we extract
+ // the load sections from the runtime linker ELF binary and embed them into each host
+ // bionic binary, omitting the PT_INTERP declaration. The kernel will treat it as a static
+ // binary, and then we use a special entry point to fix up the arguments passed by
+ // the kernel before jumping to the embedded linker.
+ linuxBionicCrtBeginSharedBinary = append(android.CopyOf(bionicCrtBeginSharedBinary),
+ "host_bionic_linker_script")
)
func init() {
@@ -76,6 +86,7 @@
type toolchainLinuxBionic struct {
toolchain64Bit
+ toolchainBionic
}
func (t *toolchainLinuxBionic) Name() string {
@@ -133,14 +144,14 @@
return nil
}
-func (t *toolchainLinuxBionic) Bionic() bool {
- return true
-}
-
func (toolchainLinuxBionic) LibclangRuntimeLibraryArch() string {
return "x86_64"
}
+func (toolchainLinuxBionic) CrtBeginSharedBinary() []string {
+ return linuxBionicCrtBeginSharedBinary
+}
+
var toolchainLinuxBionicSingleton Toolchain = &toolchainLinuxBionic{}
func linuxBionicToolchainFactory(arch android.Arch) Toolchain {
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 13b5511..c406c88 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -245,10 +245,6 @@
return linuxAvailableLibraries
}
-func (t *toolchainLinux) Bionic() bool {
- return false
-}
-
var toolchainLinuxX86Singleton Toolchain = &toolchainLinuxX86{}
var toolchainLinuxX8664Singleton Toolchain = &toolchainLinuxX8664{}
diff --git a/cc/library.go b/cc/library.go
index 5b6c623..4fd7c74 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -147,11 +147,12 @@
Cflags []string `android:"arch_variant"`
- Enabled *bool `android:"arch_variant"`
- Whole_static_libs []string `android:"arch_variant"`
- Static_libs []string `android:"arch_variant"`
- Shared_libs []string `android:"arch_variant"`
- System_shared_libs []string `android:"arch_variant"`
+ Enabled *bool `android:"arch_variant"`
+ Whole_static_libs []string `android:"arch_variant"`
+ Static_libs []string `android:"arch_variant"`
+ Shared_libs []string `android:"arch_variant"`
+ System_shared_libs []string `android:"arch_variant"`
+ Default_shared_libs []string `android:"arch_variant"`
Export_shared_lib_headers []string `android:"arch_variant"`
Export_static_lib_headers []string `android:"arch_variant"`
@@ -184,11 +185,11 @@
// be added to the include path (using -I) for this module and any module that links
// against this module. Directories listed in export_include_dirs do not need to be
// listed in local_include_dirs.
- Export_include_dirs []string `android:"arch_variant"`
+ Export_include_dirs []string `android:"arch_variant,variant_prepend"`
// list of directories that will be added to the system include path
// using -isystem for this module and any module that links against this module.
- Export_system_include_dirs []string `android:"arch_variant"`
+ Export_system_include_dirs []string `android:"arch_variant,variant_prepend"`
Target struct {
Vendor, Product struct {
@@ -1156,11 +1157,17 @@
if library.StaticProperties.Static.System_shared_libs != nil {
library.baseLinker.Properties.System_shared_libs = library.StaticProperties.Static.System_shared_libs
}
+ if library.StaticProperties.Static.Default_shared_libs != nil {
+ library.baseLinker.Properties.Default_shared_libs = library.StaticProperties.Static.Default_shared_libs
+ }
} else if library.shared() {
// Compare with nil because an empty list needs to be propagated.
if library.SharedProperties.Shared.System_shared_libs != nil {
library.baseLinker.Properties.System_shared_libs = library.SharedProperties.Shared.System_shared_libs
}
+ if library.SharedProperties.Shared.Default_shared_libs != nil {
+ library.baseLinker.Properties.Default_shared_libs = library.SharedProperties.Shared.Default_shared_libs
+ }
}
deps = library.baseLinker.linkerDeps(ctx, deps)
@@ -1174,9 +1181,9 @@
deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.StaticProperties.Static.Export_shared_lib_headers...)
deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.StaticProperties.Static.Export_static_lib_headers...)
} else if library.shared() {
- if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) {
- deps.CrtBegin = []string{"crtbegin_so"}
- deps.CrtEnd = []string{"crtend_so"}
+ if !Bool(library.baseLinker.Properties.Nocrt) {
+ deps.CrtBegin = append(deps.CrtBegin, ctx.toolchain().CrtBeginSharedLibrary()...)
+ deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtEndSharedLibrary()...)
}
deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...)
deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...)
@@ -1242,6 +1249,11 @@
} else {
specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...)
}
+ if specifiedDeps.defaultSharedLibs == nil {
+ specifiedDeps.defaultSharedLibs = properties.Default_shared_libs
+ } else {
+ specifiedDeps.defaultSharedLibs = append(specifiedDeps.defaultSharedLibs, properties.Default_shared_libs...)
+ }
specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs)
if len(specifiedDeps.systemSharedLibs) > 0 {
@@ -1249,6 +1261,11 @@
// retained.
specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs)
}
+ if len(specifiedDeps.defaultSharedLibs) > 0 {
+ // Skip this if defaultSharedLibs is either nil or [], to ensure they are
+ // retained.
+ specifiedDeps.defaultSharedLibs = android.FirstUniqueStrings(specifiedDeps.defaultSharedLibs)
+ }
return specifiedDeps
}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 9010a1a..9ad2742 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -258,6 +258,12 @@
outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
}
+ // SystemSharedLibs needs to be propagated if it's a list, even if it's empty,
+ // so check for non-nil instead of nonzero length.
+ if libInfo.DefaultSharedLibs != nil {
+ outputProperties.AddPropertyWithTag("default_shared_libs", libInfo.DefaultSharedLibs, builder.SdkMemberReferencePropertyTag(false))
+ }
+
// Map from property name to the include dirs to add to the prebuilt module in the snapshot.
includeDirs := make(map[string][]string)
@@ -387,6 +393,12 @@
// This field is exported as its contents may not be arch specific.
SystemSharedLibs []string `android:"arch_variant"`
+ // The set of default shared libraries. Note nil and [] are semantically
+ // distinct - see BaseLinkerProperties.Default_shared_libs.
+ //
+ // This field is exported as its contents may not be arch specific.
+ DefaultSharedLibs []string `android:"arch_variant"`
+
// The specific stubs version for the lib variant, or empty string if stubs
// are not in use.
//
@@ -462,6 +474,7 @@
}
}
p.SystemSharedLibs = specifiedDeps.systemSharedLibs
+ p.DefaultSharedLibs = specifiedDeps.defaultSharedLibs
}
p.ExportedGeneratedHeaders = exportedInfo.GeneratedHeaders
diff --git a/cc/linkable.go b/cc/linkable.go
index 0a5d16c..231626e 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -165,6 +165,9 @@
// "product_specific: true" modules are included here.
UseVndk() bool
+ // Bootstrap tests if this module is allowed to use non-APEX version of libraries.
+ Bootstrap() bool
+
// IsVndkSp returns true if this is a VNDK-SP module.
IsVndkSp() bool
diff --git a/cc/linker.go b/cc/linker.go
index d9ee0cf..13df232 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -45,11 +45,18 @@
// list of module-specific flags that will be used for all link steps
Ldflags []string `android:"arch_variant"`
- // list of system libraries that will be dynamically linked to
- // shared library and executable modules. If unset, generally defaults to libc,
- // libm, and libdl. Set to [] to prevent linking against the defaults.
+ // list of system libraries that will be dynamically linked to shared library and executable
+ // modules that build against bionic (device or Linux bionic modules). If unset, generally
+ // defaults to libc, libm, and libdl. Set to [] to prevent linking against the defaults.
+ // Equivalent to default_shared_libs for modules that build against bionic, and ignored on
+ // modules that do not build against bionic.
System_shared_libs []string `android:"arch_variant"`
+ // list of system libraries that will be dynamically linked to shared library and executable
+ // modules. If unset, generally defaults to libc, libm, and libdl. Set to [] to prevent
+ // linking against the defaults. Equivalent to system_shared_libs, but applies to all modules.
+ Default_shared_libs []string `android:"arch_variant"`
+
// allow the module to contain undefined symbols. By default,
// modules cannot contain undefined symbols that are not satisified by their immediate
// dependencies. Set this flag to true to remove --no-undefined from the linker flags.
@@ -231,6 +238,19 @@
linker.Properties.Ldflags = append(linker.Properties.Ldflags, flags...)
}
+// overrideDefaultSharedLibraries returns the contents of the default_shared_libs or
+// system_shared_libs properties, and records an error if both are set.
+func (linker *baseLinker) overrideDefaultSharedLibraries(ctx BaseModuleContext) []string {
+ if linker.Properties.System_shared_libs != nil && linker.Properties.Default_shared_libs != nil {
+ ctx.PropertyErrorf("system_shared_libs", "cannot be specified if default_shared_libs is also specified")
+ }
+ if ctx.toolchain().Bionic() && linker.Properties.System_shared_libs != nil {
+ // system_shared_libs is only honored when building against bionic.
+ return linker.Properties.System_shared_libs
+ }
+ return linker.Properties.Default_shared_libs
+}
+
// linkerInit initializes dynamic properties of the linker (such as runpath).
func (linker *baseLinker) linkerInit(ctx BaseModuleContext) {
if ctx.toolchain().Is64Bit() {
@@ -331,22 +351,22 @@
deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Platform.Shared_libs...)
}
+ deps.SystemSharedLibs = linker.overrideDefaultSharedLibraries(ctx)
+ // In Bazel conversion mode, variations have not been specified, so SystemSharedLibs may
+ // inaccuarately appear unset, which can cause issues with circular dependencies.
+ if deps.SystemSharedLibs == nil && !ctx.BazelConversionMode() {
+ // Provide a default set of shared libraries if default_shared_libs and system_shared_libs
+ // are unspecified. Note: If an empty list [] is specified, it implies that the module
+ // declines the default shared libraries.
+ deps.SystemSharedLibs = append(deps.SystemSharedLibs, ctx.toolchain().DefaultSharedLibraries()...)
+ }
+
if ctx.toolchain().Bionic() {
// libclang_rt.builtins has to be last on the command line
if !Bool(linker.Properties.No_libcrt) && !ctx.header() {
deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
}
- deps.SystemSharedLibs = linker.Properties.System_shared_libs
- // In Bazel conversion mode, variations have not been specified, so SystemSharedLibs may
- // inaccuarately appear unset, which can cause issues with circular dependencies.
- if deps.SystemSharedLibs == nil && !ctx.BazelConversionMode() {
- // Provide a default system_shared_libs if it is unspecified. Note: If an
- // empty list [] is specified, it implies that the module declines the
- // default system_shared_libs.
- deps.SystemSharedLibs = []string{"libc", "libm", "libdl"}
- }
-
if inList("libdl", deps.SharedLibs) {
// If system_shared_libs has libc but not libdl, make sure shared_libs does not
// have libdl to avoid loading libdl before libc.
@@ -365,10 +385,10 @@
indexList("libdl", deps.SystemSharedLibs) < indexList("libc", deps.SystemSharedLibs) {
ctx.PropertyErrorf("system_shared_libs", "libdl must be after libc")
}
-
- deps.LateSharedLibs = append(deps.LateSharedLibs, deps.SystemSharedLibs...)
}
+ deps.LateSharedLibs = append(deps.LateSharedLibs, deps.SystemSharedLibs...)
+
if ctx.Fuchsia() {
if ctx.ModuleName() != "libbioniccompat" &&
ctx.ModuleName() != "libcompiler_rt-extras" &&
@@ -573,6 +593,11 @@
} else {
specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...)
}
+ if specifiedDeps.defaultSharedLibs == nil {
+ specifiedDeps.defaultSharedLibs = linker.Properties.Default_shared_libs
+ } else {
+ specifiedDeps.defaultSharedLibs = append(specifiedDeps.defaultSharedLibs, linker.Properties.Default_shared_libs...)
+ }
return specifiedDeps
}
diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py
index 09551ea..c8cd056 100755
--- a/cc/ndkstubgen/test_ndkstubgen.py
+++ b/cc/ndkstubgen/test_ndkstubgen.py
@@ -413,6 +413,40 @@
""")
self.assertEqual(expected_version, version_file.getvalue())
+ def test_empty_stub(self) -> None:
+ """Tests that empty stubs can be generated.
+
+ This is not a common case, but libraries whose only behavior is to
+ interpose symbols to alter existing behavior do not need to expose
+ their interposing symbols as API, so it's possible for the stub to be
+ empty while still needing a stub to link against. libsigchain is an
+ example of this.
+ """
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ local:
+ *;
+ };
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, Arch('arm'),
+ 9, llndk=False, apex=True)
+ versions = parser.parse()
+
+ src_file = io.StringIO()
+ version_file = io.StringIO()
+ symbol_list_file = io.StringIO()
+ generator = ndkstubgen.Generator(src_file,
+ version_file,
+ symbol_list_file,
+ Arch('arm'),
+ 9,
+ llndk=False,
+ apex=True)
+ generator.write(versions)
+
+ self.assertEqual('', src_file.getvalue())
+ self.assertEqual('', version_file.getvalue())
+
def main() -> None:
suite = unittest.TestLoader().loadTestsFromName(__name__)
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index f126346..4430fc3 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -15,6 +15,8 @@
package cc
import (
+ "fmt"
+ "strings"
"testing"
"android/soong/android"
@@ -202,3 +204,302 @@
t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) })
t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") })
}
+
+type MemtagNoteType int
+
+const (
+ None MemtagNoteType = iota + 1
+ Sync
+ Async
+)
+
+func (t MemtagNoteType) str() string {
+ switch t {
+ case None:
+ return "none"
+ case Sync:
+ return "sync"
+ case Async:
+ return "async"
+ default:
+ panic("invalid note type")
+ }
+}
+
+func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNoteType) {
+ note_async := "note_memtag_heap_async"
+ note_sync := "note_memtag_heap_sync"
+
+ found := None
+ implicits := m.Rule("ld").Implicits
+ for _, lib := range implicits {
+ if strings.Contains(lib.Rel(), note_async) {
+ found = Async
+ break
+ } else if strings.Contains(lib.Rel(), note_sync) {
+ found = Sync
+ break
+ }
+ }
+
+ if found != expected {
+ t.Errorf("Wrong Memtag note in target %q: found %q, expected %q", m.Module().(*Module).Name(), found.str(), expected.str())
+ }
+}
+
+var prepareForTestWithMemtagHeap = android.GroupFixturePreparers(
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ templateBp := `
+ cc_test {
+ name: "%[1]s_test",
+ gtest: false,
+ }
+
+ cc_test {
+ name: "%[1]s_test_false",
+ gtest: false,
+ sanitize: { memtag_heap: false },
+ }
+
+ cc_test {
+ name: "%[1]s_test_true",
+ gtest: false,
+ sanitize: { memtag_heap: true },
+ }
+
+ cc_test {
+ name: "%[1]s_test_true_nodiag",
+ gtest: false,
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ cc_test {
+ name: "%[1]s_test_true_diag",
+ gtest: false,
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
+ }
+
+ cc_binary {
+ name: "%[1]s_binary",
+ }
+
+ cc_binary {
+ name: "%[1]s_binary_false",
+ sanitize: { memtag_heap: false },
+ }
+
+ cc_binary {
+ name: "%[1]s_binary_true",
+ sanitize: { memtag_heap: true },
+ }
+
+ cc_binary {
+ name: "%[1]s_binary_true_nodiag",
+ sanitize: { memtag_heap: true, diag: { memtag_heap: false } },
+ }
+
+ cc_binary {
+ name: "%[1]s_binary_true_diag",
+ sanitize: { memtag_heap: true, diag: { memtag_heap: true } },
+ }
+ `
+ subdirDefaultBp := fmt.Sprintf(templateBp, "default")
+ subdirExcludeBp := fmt.Sprintf(templateBp, "exclude")
+ subdirSyncBp := fmt.Sprintf(templateBp, "sync")
+ subdirAsyncBp := fmt.Sprintf(templateBp, "async")
+
+ fs.Merge(android.MockFS{
+ "subdir_default/Android.bp": []byte(subdirDefaultBp),
+ "subdir_exclude/Android.bp": []byte(subdirExcludeBp),
+ "subdir_sync/Android.bp": []byte(subdirSyncBp),
+ "subdir_async/Android.bp": []byte(subdirAsyncBp),
+ })
+ }),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.MemtagHeapExcludePaths = []string{"subdir_exclude"}
+ // "subdir_exclude" is covered by both include and exclude paths. Exclude wins.
+ variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_exclude"}
+ variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_exclude"}
+ }),
+)
+
+func TestSanitizeMemtagHeap(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ prepareForTestWithMemtagHeap,
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_diag", variant), Sync)
+}
+
+func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ prepareForTestWithMemtagHeap,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"memtag_heap"}
+ }),
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_diag", variant), Sync)
+}
+
+func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) {
+ variant := "android_arm64_armv8-a"
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ prepareForTestWithMemtagHeap,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"memtag_heap"}
+ variables.SanitizeDeviceDiag = []string{"memtag_heap"}
+ }),
+ ).RunTest(t)
+ ctx := result.TestContext
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("default_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("exclude_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("async_binary_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_test_true_diag", variant), Sync)
+
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_false", variant), None)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true", variant), Sync)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_nodiag", variant), Async)
+ checkHasMemtagNote(t, ctx.ModuleForTests("sync_binary_true_diag", variant), Sync)
+}
diff --git a/dexpreopt/OWNERS b/dexpreopt/OWNERS
index 166472f..5a2a198 100644
--- a/dexpreopt/OWNERS
+++ b/dexpreopt/OWNERS
@@ -1 +1 @@
-per-file * = ngeoffray@google.com,calin@google.com,mathieuc@google.com
+per-file * = ngeoffray@google.com,calin@google.com,skvadrik@google.com
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 77dae75..8372a64 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -211,6 +211,22 @@
return g.outputDeps
}
+func (g *Module) OutputFiles(tag string) (android.Paths, error) {
+ if tag == "" {
+ return append(android.Paths{}, g.outputFiles...), nil
+ }
+ // otherwise, tag should match one of outputs
+ for _, outputFile := range g.outputFiles {
+ if outputFile.Rel() == tag {
+ return android.Paths{outputFile}, nil
+ }
+ }
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+}
+
+var _ android.SourceFileProducer = (*Module)(nil)
+var _ android.OutputFileProducer = (*Module)(nil)
+
func toolDepsMutator(ctx android.BottomUpMutatorContext) {
if g, ok := ctx.Module().(*Module); ok {
for _, tool := range g.properties.Tools {
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 3ce4f85..714d2f8 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -31,12 +31,12 @@
var prepareForGenRuleTest = android.GroupFixturePreparers(
android.PrepareForTestWithArchMutator,
android.PrepareForTestWithDefaults,
-
android.PrepareForTestWithFilegroup,
PrepareForTestWithGenRuleBuildComponents,
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("tool", toolFactory)
ctx.RegisterModuleType("output", outputProducerFactory)
+ ctx.RegisterModuleType("use_source", useSourceFactory)
}),
android.FixtureMergeMockFs(android.MockFS{
"tool": nil,
@@ -684,6 +684,42 @@
}
}
+func TestGenruleOutputFiles(t *testing.T) {
+ bp := `
+ genrule {
+ name: "gen",
+ out: ["foo", "sub/bar"],
+ cmd: "echo foo > $(location foo) && echo bar > $(location sub/bar)",
+ }
+ use_source {
+ name: "gen_foo",
+ srcs: [":gen{foo}"],
+ }
+ use_source {
+ name: "gen_bar",
+ srcs: [":gen{sub/bar}"],
+ }
+ use_source {
+ name: "gen_all",
+ srcs: [":gen"],
+ }
+ `
+
+ result := prepareForGenRuleTest.RunTestWithBp(t, testGenruleBp()+bp)
+ android.AssertPathsRelativeToTopEquals(t,
+ "genrule.tag with output",
+ []string{"out/soong/.intermediates/gen/gen/foo"},
+ result.ModuleForTests("gen_foo", "").Module().(*useSource).srcs)
+ android.AssertPathsRelativeToTopEquals(t,
+ "genrule.tag with output in subdir",
+ []string{"out/soong/.intermediates/gen/gen/sub/bar"},
+ result.ModuleForTests("gen_bar", "").Module().(*useSource).srcs)
+ android.AssertPathsRelativeToTopEquals(t,
+ "genrule.tag with all",
+ []string{"out/soong/.intermediates/gen/gen/foo", "out/soong/.intermediates/gen/gen/sub/bar"},
+ result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
+}
+
func TestGenruleWithBazel(t *testing.T) {
bp := `
genrule {
@@ -750,3 +786,22 @@
}
var _ android.OutputFileProducer = (*testOutputProducer)(nil)
+
+type useSource struct {
+ android.ModuleBase
+ props struct {
+ Srcs []string `android:"path"`
+ }
+ srcs android.Paths
+}
+
+func (s *useSource) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ s.srcs = android.PathsForModuleSrc(ctx, s.props.Srcs)
+}
+
+func useSourceFactory() android.Module {
+ module := &useSource{}
+ module.AddProperties(&module.props)
+ android.InitAndroidModule(module)
+ return module
+}
diff --git a/java/Android.bp b/java/Android.bp
index 5952602..e5b8f96 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -93,6 +93,7 @@
"plugin_test.go",
"rro_test.go",
"sdk_test.go",
+ "sdk_library_test.go",
"system_modules_test.go",
"systemserver_classpath_fragment_test.go",
],
diff --git a/java/OWNERS b/java/OWNERS
index 16ef4d8..5242712 100644
--- a/java/OWNERS
+++ b/java/OWNERS
@@ -1 +1 @@
-per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,mathieuc@google.com
+per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,skvadrik@google.com
diff --git a/java/app_import.go b/java/app_import.go
index 6fe6204..5a87b07 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -61,7 +61,7 @@
type AndroidAppImportProperties struct {
// A prebuilt apk to import
- Apk *string
+ Apk *string `android:"path"`
// The name of a certificate in the default certificate directory or an android_app_certificate
// module name in the form ":module". Should be empty if presigned or default_dev_cert is set.
diff --git a/java/base.go b/java/base.go
index a251c3f..6b81196 100644
--- a/java/base.go
+++ b/java/base.go
@@ -870,6 +870,7 @@
if aaptSrcJar != nil {
srcJars = append(srcJars, aaptSrcJar)
}
+ srcFiles = srcFiles.FilterOutByExt(".srcjar")
if j.properties.Jarjar_rules != nil {
j.expandJarjarRules = android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
@@ -1292,6 +1293,7 @@
j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion(ctx))
j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion(ctx))
j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion(ctx))
+ j.linter.compileSdkKind = j.SdkVersion(ctx).Kind
j.linter.javaLanguageLevel = flags.javaVersion.String()
j.linter.kotlinLanguageLevel = "1.3"
if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() {
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index ccb69a0..4108770 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -227,13 +227,13 @@
Core_platform_api BootclasspathNestedAPIProperties
}
-// sdkKindToStubLibs calculates the stub library modules for each relevant android.SdkKind from the
+// apiScopeToStubLibs calculates the stub library modules for each relevant *HiddenAPIScope from the
// Stub_libs properties.
-func (p BootclasspathAPIProperties) sdkKindToStubLibs() map[android.SdkKind][]string {
- m := map[android.SdkKind][]string{}
- for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} {
- m[kind] = p.Api.Stub_libs
+func (p BootclasspathAPIProperties) apiScopeToStubLibs() map[*HiddenAPIScope][]string {
+ m := map[*HiddenAPIScope][]string{}
+ for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
+ m[apiScope] = p.Api.Stub_libs
}
- m[android.SdkCorePlatform] = p.Core_platform_api.Stub_libs
+ m[CorePlatformHiddenAPIScope] = p.Core_platform_api.Stub_libs
return m
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index c7249b0..515dd89 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -121,8 +121,18 @@
BootclasspathFragmentCoverageAffectedProperties
Coverage BootclasspathFragmentCoverageAffectedProperties
+ // Hidden API related properties.
Hidden_api HiddenAPIFlagFileProperties
+ // The list of additional stub libraries which this fragment's contents use but which are not
+ // provided by another bootclasspath_fragment.
+ //
+ // Note, "android-non-updatable" is treated specially. While no such module exists it is treated
+ // as if it was a java_sdk_library. So, when public API stubs are needed then it will be replaced
+ // with "android-non-updatable.stubs", with "androidn-non-updatable.system.stubs" when the system
+ // stubs are needed and so on.
+ Additional_stubs []string
+
// Properties that allow a fragment to depend on other fragments. This is needed for hidden API
// processing as it needs access to all the classes used by a fragment including those provided
// by other fragments.
@@ -378,7 +388,16 @@
func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies onto all the modules that provide the API stubs for classes on this
// bootclasspath fragment.
- hiddenAPIAddStubLibDependencies(ctx, b.properties.sdkKindToStubLibs())
+ hiddenAPIAddStubLibDependencies(ctx, b.properties.apiScopeToStubLibs())
+
+ for _, additionalStubModule := range b.properties.Additional_stubs {
+ for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
+ // Add a dependency onto a possibly scope specific stub library.
+ scopeSpecificDependency := apiScope.scopeSpecificStubModule(ctx, additionalStubModule)
+ tag := hiddenAPIStubsDependencyTag{apiScope: apiScope, fromAdditionalDependency: true}
+ ctx.AddVariationDependencies(nil, tag, scopeSpecificDependency)
+ }
+ }
if SkipDexpreoptBootJars(ctx) {
return
@@ -595,7 +614,7 @@
// Other bootclasspath_fragments that depend on this need the transitive set of stub dex jars
// from this to resolve any references from their code to classes provided by this fragment
// and the fragments this depends upon.
- TransitiveStubDexJarsByKind: input.transitiveStubDexJarsByKind(),
+ TransitiveStubDexJarsByScope: input.transitiveStubDexJarsByScope(),
}
// The monolithic hidden API processing also needs access to all the output files produced by
@@ -639,8 +658,8 @@
// Populate with flag file paths from the properties.
input.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
- // Store the stub dex jars from this module's fragment dependencies.
- input.DependencyStubDexJarsByKind = dependencyHiddenApiInfo.TransitiveStubDexJarsByKind
+ // Add the stub dex jars from this module's fragment dependencies.
+ input.DependencyStubDexJarsByScope.addStubDexJarsByModule(dependencyHiddenApiInfo.TransitiveStubDexJarsByScope)
return input
}
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index fba7d1a..b469886 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -245,17 +245,34 @@
otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs/android_common/dex/myothersdklibrary.stubs.jar"
// Check that SdkPublic uses public stubs for all sdk libraries.
- android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkPublic])
+ android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(PublicHiddenAPIScope))
// Check that SdkSystem uses system stubs for mysdklibrary and public stubs for myothersdklibrary
// as it does not provide system stubs.
- android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkSystem])
+ android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(SystemHiddenAPIScope))
// Check that SdkTest also uses system stubs for mysdklibrary as it does not provide test stubs
// and public stubs for myothersdklibrary as it does not provide test stubs either.
- android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByKind[android.SdkTest])
+ android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(TestHiddenAPIScope))
// Check that SdkCorePlatform uses public stubs from the mycoreplatform library.
corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar"
- android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByKind[android.SdkCorePlatform])
+ android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(CorePlatformHiddenAPIScope))
+
+ // Check the widest stubs.. The list contains the widest stub dex jar provided by each module.
+ expectedWidestPaths := []string{
+ // mycoreplatform's widest API is core platform.
+ corePlatformStubsJar,
+
+ // myothersdklibrary's widest API is public.
+ otherPublicStubsJar,
+
+ // sdklibrary's widest API is system.
+ systemStubsJar,
+
+ // mystublib's only provides one API and so it must be the widest.
+ stubsJar,
+ }
+
+ android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope())
}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 6e22614..0895951 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -25,9 +25,160 @@
// Contains support for processing hiddenAPI in a modular fashion.
+// HiddenAPIScope encapsulates all the information that the hidden API processing needs about API
+// scopes, i.e. what is called android.SdkKind and apiScope. It does not just use those as they do
+// not provide the information needed by hidden API processing.
+type HiddenAPIScope struct {
+ // The name of the scope, used for debug purposes.
+ name string
+
+ // The corresponding android.SdkKind, used for retrieving paths from java_sdk_library* modules.
+ sdkKind android.SdkKind
+
+ // The option needed to passed to "hiddenapi list".
+ hiddenAPIListOption string
+
+ // The name sof the source stub library modules that contain the API provided by the platform,
+ // i.e. by modules that are not in an APEX.
+ nonUpdatableSourceModule string
+
+ // The names of the prebuilt stub library modules that contain the API provided by the platform,
+ // i.e. by modules that are not in an APEX.
+ nonUpdatablePrebuiltModule string
+}
+
+// initHiddenAPIScope initializes the scope.
+func initHiddenAPIScope(apiScope *HiddenAPIScope) *HiddenAPIScope {
+ sdkKind := apiScope.sdkKind
+ // The platform does not provide a core platform API.
+ if sdkKind != android.SdkCorePlatform {
+ kindAsString := sdkKind.String()
+ var insert string
+ if sdkKind == android.SdkPublic {
+ insert = ""
+ } else {
+ insert = "." + strings.ReplaceAll(kindAsString, "-", "_")
+ }
+
+ nonUpdatableModule := "android-non-updatable"
+
+ // Construct the name of the android-non-updatable source module for this scope.
+ apiScope.nonUpdatableSourceModule = fmt.Sprintf("%s.stubs%s", nonUpdatableModule, insert)
+
+ prebuiltModuleName := func(name string, kind string) string {
+ return fmt.Sprintf("sdk_%s_current_%s", kind, name)
+ }
+
+ // Construct the name of the android-non-updatable prebuilt module for this scope.
+ apiScope.nonUpdatablePrebuiltModule = prebuiltModuleName(nonUpdatableModule, kindAsString)
+ }
+
+ return apiScope
+}
+
+// android-non-updatable takes the name of a module and returns a possibly scope specific name of
+// the module.
+func (l *HiddenAPIScope) scopeSpecificStubModule(ctx android.BaseModuleContext, name string) string {
+ // The android-non-updatable is not a java_sdk_library but there are separate stub libraries for
+ // each scope.
+ // TODO(b/192067200): Remove special handling of android-non-updatable.
+ if name == "android-non-updatable" {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
+ return l.nonUpdatablePrebuiltModule
+ } else {
+ return l.nonUpdatableSourceModule
+ }
+ } else {
+ // Assume that the module is either a java_sdk_library (or equivalent) and so will provide
+ // separate stub jars for each scope or is a java_library (or equivalent) in which case it will
+ // have the same stub jar for each scope.
+ return name
+ }
+}
+
+func (l *HiddenAPIScope) String() string {
+ return fmt.Sprintf("HiddenAPIScope{%s}", l.name)
+}
+
+var (
+ PublicHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
+ name: "public",
+ sdkKind: android.SdkPublic,
+ hiddenAPIListOption: "--public-stub-classpath",
+ })
+ SystemHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
+ name: "system",
+ sdkKind: android.SdkSystem,
+ hiddenAPIListOption: "--system-stub-classpath",
+ })
+ TestHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
+ name: "test",
+ sdkKind: android.SdkTest,
+ hiddenAPIListOption: "--test-stub-classpath",
+ })
+ ModuleLibHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
+ name: "module-lib",
+ sdkKind: android.SdkModule,
+ })
+ CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
+ name: "core-platform",
+ sdkKind: android.SdkCorePlatform,
+ hiddenAPIListOption: "--core-platform-stub-classpath",
+ })
+
+ // hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
+ // API processing.
+ //
+ // These are roughly in order from narrowest API surface to widest. Widest means the API stubs
+ // with the biggest API surface, e.g. test is wider than system is wider than public.
+ //
+ // Core platform is considered wider than system/module-lib because those modules that provide
+ // core platform APIs either do not have any system/module-lib APIs at all, or if they do it is
+ // because the core platform API is being converted to system/module-lib APIs. In either case the
+ // system/module-lib APIs are subsets of the core platform API.
+ //
+ // This is not strictly in order from narrowest to widest as the Test API is wider than system but
+ // is neither wider or narrower than the module-lib or core platform APIs. However, this works
+ // well enough at the moment.
+ // TODO(b/191644675): Correctly reflect the sub/superset relationships between APIs.
+ hiddenAPIScopes = []*HiddenAPIScope{
+ PublicHiddenAPIScope,
+ SystemHiddenAPIScope,
+ TestHiddenAPIScope,
+ ModuleLibHiddenAPIScope,
+ CorePlatformHiddenAPIScope,
+ }
+
+ // The HiddenAPIScope instances that are supported by a java_sdk_library.
+ //
+ // CorePlatformHiddenAPIScope is not used as the java_sdk_library does not have special support
+ // for core_platform API, instead it is implemented as a customized form of PublicHiddenAPIScope.
+ hiddenAPISdkLibrarySupportedScopes = []*HiddenAPIScope{
+ PublicHiddenAPIScope,
+ SystemHiddenAPIScope,
+ TestHiddenAPIScope,
+ ModuleLibHiddenAPIScope,
+ }
+
+ // The HiddenAPIScope instances that are supported by the `hiddenapi list`.
+ hiddenAPIFlagScopes = []*HiddenAPIScope{
+ PublicHiddenAPIScope,
+ SystemHiddenAPIScope,
+ TestHiddenAPIScope,
+ CorePlatformHiddenAPIScope,
+ }
+)
+
type hiddenAPIStubsDependencyTag struct {
blueprint.BaseDependencyTag
- sdkKind android.SdkKind
+
+ // The api scope for which this dependency was added.
+ apiScope *HiddenAPIScope
+
+ // Indicates that the dependency is not for an API provided by the current bootclasspath fragment
+ // but is an additional API provided by a module that is not part of the current bootclasspath
+ // fragment.
+ fromAdditionalDependency bool
}
func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() {
@@ -38,6 +189,11 @@
}
func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
+ // Do not add additional dependencies to the sdk.
+ if b.fromAdditionalDependency {
+ return nil
+ }
+
// If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs
// property, otherwise treat if it was specified in the java_header_libs property.
if javaSdkLibrarySdkMemberType.IsInstance(child) {
@@ -65,24 +221,9 @@
var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{}
var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{}
-// hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
-// API processing.
-//
-// These are in order from narrowest API surface to widest. Widest means the API stubs with the
-// biggest API surface, e.g. test is wider than system is wider than public. Core platform is
-// considered wider than test even though it has no relationship with test because the libraries
-// that provide core platform API don't provide test. While the core platform API is being converted
-// to a system API the system API is still a subset of core platform.
-var hiddenAPIRelevantSdkKinds = []android.SdkKind{
- android.SdkPublic,
- android.SdkSystem,
- android.SdkTest,
- android.SdkCorePlatform,
-}
-
// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs
// needed to produce the hidden API monolithic stub flags file.
-func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[android.SdkKind][]string {
+func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[*HiddenAPIScope][]string {
var publicStubModules []string
var systemStubModules []string
var testStubModules []string
@@ -115,22 +256,22 @@
testStubModules = append(testStubModules, "jacoco-stubs")
}
- m := map[android.SdkKind][]string{}
- m[android.SdkPublic] = publicStubModules
- m[android.SdkSystem] = systemStubModules
- m[android.SdkTest] = testStubModules
- m[android.SdkCorePlatform] = corePlatformStubModules
+ m := map[*HiddenAPIScope][]string{}
+ m[PublicHiddenAPIScope] = publicStubModules
+ m[SystemHiddenAPIScope] = systemStubModules
+ m[TestHiddenAPIScope] = testStubModules
+ m[CorePlatformHiddenAPIScope] = corePlatformStubModules
return m
}
// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in
-// sdkKindToStubLibModules. It adds them in a well known order and uses an SdkKind specific tag to
-// identify the source of the dependency.
-func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, sdkKindToStubLibModules map[android.SdkKind][]string) {
+// apiScopeToStubLibModules. It adds them in a well known order and uses a HiddenAPIScope specific
+// tag to identify the source of the dependency.
+func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScopeToStubLibModules map[*HiddenAPIScope][]string) {
module := ctx.Module()
- for _, sdkKind := range hiddenAPIRelevantSdkKinds {
- modules := sdkKindToStubLibModules[sdkKind]
- ctx.AddDependency(module, hiddenAPIStubsDependencyTag{sdkKind: sdkKind}, modules...)
+ for _, apiScope := range hiddenAPIScopes {
+ modules := apiScopeToStubLibModules[apiScope]
+ ctx.AddDependency(module, hiddenAPIStubsDependencyTag{apiScope: apiScope}, modules...)
}
}
@@ -153,33 +294,21 @@
return dexJar
}
-var sdkKindToHiddenapiListOption = map[android.SdkKind]string{
- android.SdkPublic: "public-stub-classpath",
- android.SdkSystem: "system-stub-classpath",
- android.SdkTest: "test-stub-classpath",
- android.SdkCorePlatform: "core-platform-stub-classpath",
-}
-
-// ruleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
+// buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
//
// The rule is initialized but not built so that the caller can modify it and select an appropriate
// name.
-func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput) *android.RuleBuilder {
+func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, moduleStubFlagsPaths android.Paths) {
// Singleton rule which applies hiddenapi on all boot class path dex files.
rule := android.NewRuleBuilder(pctx, ctx)
tempPath := tempPathForRestat(ctx, outputPath)
// Find the widest API stubs provided by the fragments on which this depends, if any.
- var dependencyStubDexJars android.Paths
- for i := len(hiddenAPIRelevantSdkKinds) - 1; i >= 0; i-- {
- kind := hiddenAPIRelevantSdkKinds[i]
- stubsForKind := input.DependencyStubDexJarsByKind[kind]
- if len(stubsForKind) != 0 {
- dependencyStubDexJars = stubsForKind
- break
- }
- }
+ dependencyStubDexJars := input.DependencyStubDexJarsByScope.StubDexJarsForWidestAPIScope()
+
+ // Add widest API stubs from the additional dependencies of this, if any.
+ dependencyStubDexJars = append(dependencyStubDexJars, input.AdditionalStubDexJarsByScope.StubDexJarsForWidestAPIScope()...)
command := rule.Command().
Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
@@ -187,24 +316,46 @@
FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
FlagForEachInput("--boot-dex=", bootDexJars)
- // Iterate over the sdk kinds in a fixed order.
- for _, sdkKind := range hiddenAPIRelevantSdkKinds {
- // Merge in the stub dex jar paths for this kind from the fragments on which it depends. They
- // will be needed to resolve dependencies from this fragment's stubs to classes in the other
- // fragment's APIs.
- dependencyPaths := input.DependencyStubDexJarsByKind[sdkKind]
- paths := append(dependencyPaths, input.StubDexJarsByKind[sdkKind]...)
+ // If no module stub flags paths are provided then this must be being called for a
+ // bootclasspath_fragment and not the whole platform_bootclasspath.
+ if moduleStubFlagsPaths == nil {
+ // This is being run on a fragment of the bootclasspath.
+ command.Flag("--fragment")
+ }
+
+ // Iterate over the api scopes in a fixed order.
+ for _, apiScope := range hiddenAPIFlagScopes {
+ // Merge in the stub dex jar paths for this api scope from the fragments on which it depends.
+ // They will be needed to resolve dependencies from this fragment's stubs to classes in the
+ // other fragment's APIs.
+ var paths android.Paths
+ paths = append(paths, input.DependencyStubDexJarsByScope.StubDexJarsForScope(apiScope)...)
+ paths = append(paths, input.AdditionalStubDexJarsByScope.StubDexJarsForScope(apiScope)...)
+ paths = append(paths, input.StubDexJarsByScope.StubDexJarsForScope(apiScope)...)
if len(paths) > 0 {
- option := sdkKindToHiddenapiListOption[sdkKind]
- command.FlagWithInputList("--"+option+"=", paths, ":")
+ option := apiScope.hiddenAPIListOption
+ command.FlagWithInputList(option+"=", paths, ":")
}
}
// Add the output path.
command.FlagWithOutput("--out-api-flags=", tempPath)
+ // If there are stub flag files that have been generated by fragments on which this depends then
+ // use them to validate the stub flag file generated by the rules created by this method.
+ if len(moduleStubFlagsPaths) > 0 {
+ validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, moduleStubFlagsPaths)
+
+ // Add the file that indicates that the file generated by this is valid.
+ //
+ // This will cause the validation rule above to be run any time that the output of this rule
+ // changes but the validation will run in parallel with other rules that depend on this file.
+ command.Validation(validFile)
+ }
+
commitChangeForRestat(rule, tempPath, outputPath)
- return rule
+
+ rule.Build(name, desc)
}
// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
@@ -377,8 +528,9 @@
// that category.
FlagFilesByCategory FlagFilesByCategory
- // The paths to the stub dex jars for each of the android.SdkKind in hiddenAPIRelevantSdkKinds.
- TransitiveStubDexJarsByKind StubDexJarsByKind
+ // The paths to the stub dex jars for each of the *HiddenAPIScope in hiddenAPIScopes provided by
+ // this fragment and the fragments on which this depends.
+ TransitiveStubDexJarsByScope StubDexJarsByModule
// The output from the hidden API processing needs to be made available to other modules.
HiddenAPIFlagOutput
@@ -386,8 +538,8 @@
func newHiddenAPIInfo() *HiddenAPIInfo {
info := HiddenAPIInfo{
- FlagFilesByCategory: FlagFilesByCategory{},
- TransitiveStubDexJarsByKind: StubDexJarsByKind{},
+ FlagFilesByCategory: FlagFilesByCategory{},
+ TransitiveStubDexJarsByScope: StubDexJarsByModule{},
}
return &info
}
@@ -398,34 +550,111 @@
for _, fragment := range fragments {
if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
- i.TransitiveStubDexJarsByKind.append(info.TransitiveStubDexJarsByKind)
+ i.TransitiveStubDexJarsByScope.addStubDexJarsByModule(info.TransitiveStubDexJarsByScope)
}
}
-
- // Dedup and sort paths.
- i.TransitiveStubDexJarsByKind.dedupAndSort()
}
var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
-// StubDexJarsByKind maps an android.SdkKind to the paths to stub dex jars appropriate for that
-// level. See hiddenAPIRelevantSdkKinds for a list of the acceptable android.SdkKind values.
-type StubDexJarsByKind map[android.SdkKind]android.Paths
+// ModuleStubDexJars contains the stub dex jars provided by a single module.
+//
+// It maps a *HiddenAPIScope to the path to stub dex jars appropriate for that scope. See
+// hiddenAPIScopes for a list of the acceptable *HiddenAPIScope values.
+type ModuleStubDexJars map[*HiddenAPIScope]android.Path
-// append appends the supplied kind specific stub dex jar pargs to the corresponding kind in this
+// stubDexJarForWidestAPIScope returns the stub dex jars for the widest API scope provided by this
// map.
-func (s StubDexJarsByKind) append(other StubDexJarsByKind) {
- for _, kind := range hiddenAPIRelevantSdkKinds {
- s[kind] = append(s[kind], other[kind]...)
+//
+// The relative width of APIs is determined by their order in hiddenAPIScopes.
+func (s ModuleStubDexJars) stubDexJarForWidestAPIScope() android.Path {
+ for i := len(hiddenAPIScopes) - 1; i >= 0; i-- {
+ apiScope := hiddenAPIScopes[i]
+ if stubsForAPIScope, ok := s[apiScope]; ok {
+ return stubsForAPIScope
+ }
+ }
+
+ return nil
+}
+
+// StubDexJarsByModule contains the stub dex jars provided by a set of modules.
+//
+// It maps a module name to the path to the stub dex jars provided by that module.
+type StubDexJarsByModule map[string]ModuleStubDexJars
+
+// addStubDexJar adds a stub dex jar path provided by the specified module for the specified scope.
+func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.Module, scope *HiddenAPIScope, stubDexJar android.Path) {
+ name := android.RemoveOptionalPrebuiltPrefix(module.Name())
+ if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule {
+ // Treat all *android-non-updatable* modules as if they were part of an android-non-updatable
+ // java_sdk_library.
+ // TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent.
+ name = "android-non-updatable"
+ } else if name == "legacy.art.module.platform.api" {
+ // Treat legacy.art.module.platform.api as if it was an API scope provided by the
+ // art.module.public.api java_sdk_library which will be the case once the former has been
+ // migrated to a module_lib API.
+ name = "art.module.public.api"
+ } else if name == "legacy.i18n.module.platform.api" {
+ // Treat legacy.i18n.module.platform.api as if it was an API scope provided by the
+ // i18n.module.public.api java_sdk_library which will be the case once the former has been
+ // migrated to a module_lib API.
+ name = "i18n.module.public.api"
+ } else if name == "conscrypt.module.platform.api" {
+ // Treat conscrypt.module.platform.api as if it was an API scope provided by the
+ // conscrypt.module.public.api java_sdk_library which will be the case once the former has been
+ // migrated to a module_lib API.
+ name = "conscrypt.module.public.api"
+ }
+ stubDexJarsByScope := s[name]
+ if stubDexJarsByScope == nil {
+ stubDexJarsByScope = ModuleStubDexJars{}
+ s[name] = stubDexJarsByScope
+ }
+ stubDexJarsByScope[scope] = stubDexJar
+}
+
+// addStubDexJarsByModule adds the stub dex jars in the supplied StubDexJarsByModule to this map.
+func (s StubDexJarsByModule) addStubDexJarsByModule(other StubDexJarsByModule) {
+ for module, stubDexJarsByScope := range other {
+ s[module] = stubDexJarsByScope
}
}
-// dedupAndSort removes duplicates in the stub dex jar paths and sorts them into a consistent and
-// deterministic order.
-func (s StubDexJarsByKind) dedupAndSort() {
- for kind, paths := range s {
- s[kind] = android.SortedUniquePaths(paths)
+// StubDexJarsForWidestAPIScope returns a list of stub dex jars containing the widest API scope
+// provided by each module.
+//
+// The relative width of APIs is determined by their order in hiddenAPIScopes.
+func (s StubDexJarsByModule) StubDexJarsForWidestAPIScope() android.Paths {
+ stubDexJars := android.Paths{}
+ modules := android.SortedStringKeys(s)
+ for _, module := range modules {
+ stubDexJarsByScope := s[module]
+
+ stubDexJars = append(stubDexJars, stubDexJarsByScope.stubDexJarForWidestAPIScope())
}
+
+ return stubDexJars
+}
+
+// StubDexJarsForScope returns a list of stub dex jars containing the stub dex jars provided by each
+// module for the specified scope.
+//
+// If a module does not provide a stub dex jar for the supplied scope then it does not contribute to
+// the returned list.
+func (s StubDexJarsByModule) StubDexJarsForScope(scope *HiddenAPIScope) android.Paths {
+ stubDexJars := android.Paths{}
+ modules := android.SortedStringKeys(s)
+ for _, module := range modules {
+ stubDexJarsByScope := s[module]
+ // Not every module will have the same set of
+ if jars, ok := stubDexJarsByScope[scope]; ok {
+ stubDexJars = append(stubDexJars, jars)
+ }
+ }
+
+ return stubDexJars
}
// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
@@ -435,14 +664,21 @@
// from the stub dex files.
FlagFilesByCategory FlagFilesByCategory
- // StubDexJarsByKind contains the stub dex jars for different android.SdkKind and which determine
+ // StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine
// the initial flags for each dex member.
- StubDexJarsByKind StubDexJarsByKind
+ StubDexJarsByScope StubDexJarsByModule
- // DependencyStubDexJarsByKind contains the stub dex jars provided by the fragments on which this
- // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByKind from each
+ // DependencyStubDexJarsByScope contains the stub dex jars provided by the fragments on which this
+ // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByScope from each
// fragment on which this depends.
- DependencyStubDexJarsByKind StubDexJarsByKind
+ DependencyStubDexJarsByScope StubDexJarsByModule
+
+ // AdditionalStubDexJarsByScope contains stub dex jars provided by other modules in addition to
+ // the ones that are obtained from fragments on which this depends.
+ //
+ // These are kept separate from stub dex jars in HiddenAPIFlagInput.DependencyStubDexJarsByScope
+ // as there are not propagated transitively to other fragments that depend on this.
+ AdditionalStubDexJarsByScope StubDexJarsByModule
// RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
// specified in the bootclasspath_fragment's stub_libs and contents properties.
@@ -452,8 +688,10 @@
// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
func newHiddenAPIFlagInput() HiddenAPIFlagInput {
input := HiddenAPIFlagInput{
- FlagFilesByCategory: FlagFilesByCategory{},
- StubDexJarsByKind: StubDexJarsByKind{},
+ FlagFilesByCategory: FlagFilesByCategory{},
+ StubDexJarsByScope: StubDexJarsByModule{},
+ DependencyStubDexJarsByScope: StubDexJarsByModule{},
+ AdditionalStubDexJarsByScope: StubDexJarsByModule{},
}
return input
@@ -469,7 +707,7 @@
// required as the whole point of adding something to the bootclasspath fragment is to add it to
// the bootclasspath in order to be used by something else in the system. Without any stubs it
// cannot do that.
- if len(i.StubDexJarsByKind) == 0 {
+ if len(i.StubDexJarsByScope) == 0 {
return false
}
@@ -500,14 +738,15 @@
//
// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
- addFromModule := func(ctx android.ModuleContext, module android.Module, kind android.SdkKind) {
- dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
+ addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) {
+ sdkKind := apiScope.sdkKind
+ dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind)
if dexJar != nil {
- i.StubDexJarsByKind[kind] = append(i.StubDexJarsByKind[kind], dexJar)
+ i.StubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar)
}
if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
- removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, kind)
+ removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind)
i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
}
}
@@ -515,11 +754,9 @@
// If the contents includes any java_sdk_library modules then add them to the stubs.
for _, module := range contents {
if _, ok := module.(SdkLibraryDependency); ok {
- // Add information for every possible kind needed by hidden API. SdkCorePlatform is not used
- // as the java_sdk_library does not have special support for core_platform API, instead it is
- // implemented as a customized form of SdkPublic.
- for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} {
- addFromModule(ctx, module, kind)
+ // Add information for every possible API scope needed by hidden API.
+ for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
+ addFromModule(ctx, module, apiScope)
}
}
}
@@ -527,13 +764,19 @@
ctx.VisitDirectDeps(func(module android.Module) {
tag := ctx.OtherModuleDependencyTag(module)
if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
- kind := hiddenAPIStubsTag.sdkKind
- addFromModule(ctx, module, kind)
+ apiScope := hiddenAPIStubsTag.apiScope
+ if hiddenAPIStubsTag.fromAdditionalDependency {
+ dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, apiScope.sdkKind)
+ if dexJar != nil {
+ i.AdditionalStubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar)
+ }
+ } else {
+ addFromModule(ctx, module, apiScope)
+ }
}
})
// Normalize the paths, i.e. remove duplicates and sort.
- i.StubDexJarsByKind.dedupAndSort()
i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
}
@@ -546,9 +789,9 @@
}
}
-func (i *HiddenAPIFlagInput) transitiveStubDexJarsByKind() StubDexJarsByKind {
- transitive := i.DependencyStubDexJarsByKind
- transitive.append(i.StubDexJarsByKind)
+func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByModule {
+ transitive := i.DependencyStubDexJarsByScope
+ transitive.addStubDexJarsByModule(i.StubDexJarsByScope)
return transitive
}
@@ -637,28 +880,6 @@
outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
- // The file which is used to record that the flags file is valid.
- var validFile android.WritablePath
-
- // If there are flag files that have been generated by fragments on which this depends then use
- // them to validate the flag file generated by the rules created by this method.
- if len(allFlagsPaths) > 0 {
- // The flags file generated by the rule created by this method needs to be validated to ensure
- // that it is consistent with the flag files generated by the individual fragments.
-
- validFile = pathForValidation(ctx, outputPath)
-
- // Create a rule to validate the output from the following rule.
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- BuiltTool("verify_overlaps").
- Input(outputPath).
- Inputs(allFlagsPaths).
- // If validation passes then update the file that records that.
- Text("&& touch").Output(validFile)
- rule.Build(name+"Validation", desc+" validation")
- }
-
// Create the rule that will generate the flag files.
tempPath := tempPathForRestat(ctx, outputPath)
rule := android.NewRuleBuilder(pctx, ctx)
@@ -684,7 +905,11 @@
commitChangeForRestat(rule, tempPath, outputPath)
- if validFile != nil {
+ // If there are flag files that have been generated by fragments on which this depends then use
+ // them to validate the flag file generated by the rules created by this method.
+ if len(allFlagsPaths) > 0 {
+ validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, allFlagsPaths)
+
// Add the file that indicates that the file generated by this is valid.
//
// This will cause the validation rule above to be run any time that the output of this rule
@@ -695,6 +920,25 @@
rule.Build(name, desc)
}
+// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
+// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
+func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, modularFilePaths android.Paths) android.WritablePath {
+ // The file which is used to record that the flags file is valid.
+ validFile := pathForValidation(ctx, monolithicFilePath)
+
+ // Create a rule to validate the output from the following rule.
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("verify_overlaps").
+ Input(monolithicFilePath).
+ Inputs(modularFilePaths).
+ // If validation passes then update the file that records that.
+ Text("&& touch").Output(validFile)
+ rule.Build(name+"Validation", desc+" validation")
+
+ return validFile
+}
+
// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
// bootclasspath and then encode the flags into the boot dex files.
//
@@ -718,8 +962,7 @@
// Generate the stub-flags.csv.
stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
- rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input)
- rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
+ buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil)
// Extract the classes jars from the contents.
classesJars := extractClassesJarsFromModules(contents)
diff --git a/java/jacoco.go b/java/jacoco.go
index 9162161..e11c2ce 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -94,7 +94,7 @@
if len(includes) > 0 {
specs += strings.Join(includes, " ")
} else {
- specs += "**/*.class"
+ specs += "'**/*.class'"
}
return specs
}
diff --git a/java/jacoco_test.go b/java/jacoco_test.go
index 91f0553..1882908 100644
--- a/java/jacoco_test.go
+++ b/java/jacoco_test.go
@@ -74,7 +74,7 @@
{
name: "implicit wildcard",
includes: []string{},
- out: "**/*.class",
+ out: "'**/*.class'",
},
{
name: "only include",
diff --git a/java/lint.go b/java/lint.go
index 1511cfe..dd5e4fb 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -78,6 +78,7 @@
minSdkVersion string
targetSdkVersion string
compileSdkVersion string
+ compileSdkKind android.SdkKind
javaLanguageLevel string
kotlinLanguageLevel string
outputs lintOutputs
@@ -389,13 +390,25 @@
rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
+ var apiVersionsName, apiVersionsPrebuilt string
+ if l.compileSdkKind == android.SdkModule {
+ // When compiling an SDK module we use the filtered database because otherwise lint's
+ // NewApi check produces too many false positives; This database excludes information
+ // about classes created in mainline modules hence removing those false positives.
+ apiVersionsName = "api_versions_public_filtered.xml"
+ apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
+ } else {
+ apiVersionsName = "api_versions.xml"
+ apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
+ }
+
var annotationsZipPath, apiVersionsXMLPath android.Path
if ctx.Config().AlwaysUsePrebuiltSdks() {
annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
- apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
+ apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
} else {
annotationsZipPath = copiedAnnotationsZipPath(ctx)
- apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
+ apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
}
cmd := rule.Command()
@@ -487,23 +500,27 @@
l.copyLintDependencies(ctx)
}
+func findModuleOrErr(ctx android.SingletonContext, moduleName string) android.Module {
+ var res android.Module
+ ctx.VisitAllModules(func(m android.Module) {
+ if ctx.ModuleName(m) == moduleName {
+ if res == nil {
+ res = m
+ } else {
+ ctx.Errorf("lint: multiple %s modules found: %s and %s", moduleName,
+ ctx.ModuleSubDir(m), ctx.ModuleSubDir(res))
+ }
+ }
+ })
+ return res
+}
+
func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
if ctx.Config().AlwaysUsePrebuiltSdks() {
return
}
- var frameworkDocStubs android.Module
- ctx.VisitAllModules(func(m android.Module) {
- if ctx.ModuleName(m) == "framework-doc-stubs" {
- if frameworkDocStubs == nil {
- frameworkDocStubs = m
- } else {
- ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
- ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
- }
- }
- })
-
+ frameworkDocStubs := findModuleOrErr(ctx, "framework-doc-stubs")
if frameworkDocStubs == nil {
if !ctx.Config().AllowMissingDependencies() {
ctx.Errorf("lint: missing framework-doc-stubs")
@@ -511,6 +528,14 @@
return
}
+ filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
+ if filteredDb == nil {
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.Errorf("lint: missing api-versions-xml-public-filtered")
+ }
+ return
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: android.CpIfChanged,
Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
@@ -520,7 +545,13 @@
ctx.Build(pctx, android.BuildParams{
Rule: android.CpIfChanged,
Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
- Output: copiedAPIVersionsXmlPath(ctx),
+ Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
+ })
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.CpIfChanged,
+ Input: android.OutputFileForModule(ctx, filteredDb, ""),
+ Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
})
}
@@ -528,8 +559,8 @@
return android.PathForOutput(ctx, "lint", "annotations.zip")
}
-func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
- return android.PathForOutput(ctx, "lint", "api_versions.xml")
+func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
+ return android.PathForOutput(ctx, "lint", name)
}
func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 2de05b0..75de7dc 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -78,3 +78,7 @@
--disable_check HardcodedDebugMode
--warning_check QueryAllPackagesPermission
+
+--warning_check CoarseFineLocation
+--warning_check IntentFilterExportedReceiver
+--warning_check RemoteViewLayout
diff --git a/java/lint_test.go b/java/lint_test.go
index 6d64de7..9cf1c33 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -219,3 +219,72 @@
t.Error("did not restrict baselining NewApi")
}
}
+
+func TestJavaLintDatabaseSelectionFull(t *testing.T) {
+ testCases := []string{
+ "current", "core_platform", "system_current", "S", "30", "10000",
+ }
+ bp := `
+ java_library {
+ name: "foo",
+ srcs: [
+ "a.java",
+ ],
+ min_sdk_version: "29",
+ sdk_version: "XXX",
+ lint: {
+ strict_updatability_linting: true,
+ },
+ }
+`
+ for _, testCase := range testCases {
+ thisBp := strings.Replace(bp, "XXX", testCase, 1)
+
+ result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, FixtureWithPrebuiltApis(map[string][]string{
+ "30": {"foo"},
+ "10000": {"foo"},
+ })).
+ RunTestWithBp(t, thisBp)
+
+ foo := result.ModuleForTests("foo", "android_common")
+ sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
+ if strings.Contains(*sboxProto.Commands[0].Command,
+ "/api_versions_public_filtered.xml") {
+ t.Error("used public-filtered lint api database for case", testCase)
+ }
+ if !strings.Contains(*sboxProto.Commands[0].Command,
+ "/api_versions.xml") {
+ t.Error("did not use full api database for case", testCase)
+ }
+ }
+
+}
+
+func TestJavaLintDatabaseSelectionPublicFiltered(t *testing.T) {
+ bp := `
+ java_library {
+ name: "foo",
+ srcs: [
+ "a.java",
+ ],
+ min_sdk_version: "29",
+ sdk_version: "module_current",
+ lint: {
+ strict_updatability_linting: true,
+ },
+ }
+`
+ result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules).
+ RunTestWithBp(t, bp)
+
+ foo := result.ModuleForTests("foo", "android_common")
+ sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
+ if !strings.Contains(*sboxProto.Commands[0].Command,
+ "/api_versions_public_filtered.xml") {
+ t.Error("did not use public-filtered lint api database", *sboxProto.Commands[0].Command)
+ }
+ if strings.Contains(*sboxProto.Commands[0].Command,
+ "/api_versions.xml") {
+ t.Error("used full api database")
+ }
+}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index a444de0..d72cee0 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -119,8 +119,8 @@
}
// Add dependencies onto the stub lib modules.
- sdkKindToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config())
- hiddenAPIAddStubLibDependencies(ctx, sdkKindToStubLibModules)
+ apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config())
+ hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules)
}
func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
@@ -303,7 +303,7 @@
// the fragments will have already provided the flags that are needed.
classesJars := monolithicInfo.ClassesJars
- // Create the input to pass to ruleToGenerateHiddenAPIStubFlagsFile
+ // Create the input to pass to buildRuleToGenerateHiddenAPIStubFlagsFile
input := newHiddenAPIFlagInput()
// Gather stub library information from the dependencies on modules provided by
@@ -315,8 +315,7 @@
// Generate the monolithic stub-flags.csv file.
stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
- rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlags, bootDexJarByModule.bootDexJars(), input)
- rule.Build("platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags")
+ buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagsPaths)
// Generate the annotation-flags.csv file from all the module annotations.
annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv")
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 65af953..8e0618e 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -122,7 +122,7 @@
result.ModuleForTests("foo.api.system.28", "")
result.ModuleForTests("foo.api.test.28", "")
- exportedComponentsInfo := result.ModuleProvider(foo.Module(), ExportedComponentsInfoProvider).(ExportedComponentsInfo)
+ exportedComponentsInfo := result.ModuleProvider(foo.Module(), android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
expectedFooExportedComponents := []string{
"foo.stubs",
"foo.stubs.source",
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 394fcc5..31ec3f1 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -26,9 +26,18 @@
"system/logging/rust",
"system/security",
"system/tools/aidl",
+ "tools/security/fuzzing/example_rust_fuzzer",
+ }
+
+ DownstreamRustAllowedPaths = []string{
+ // Add downstream allowed Rust paths here.
}
RustModuleTypes = []string{
+ // Don't add rust_bindgen or rust_protobuf as these are code generation modules
+ // and can be expected to be in paths without Rust code.
+ "rust_benchmark",
+ "rust_benchmark_host",
"rust_binary",
"rust_binary_host",
"rust_library",
@@ -37,6 +46,7 @@
"rust_ffi",
"rust_ffi_shared",
"rust_ffi_static",
+ "rust_fuzz",
"rust_library_host",
"rust_library_host_dylib",
"rust_library_host_rlib",
diff --git a/rust/rust.go b/rust/rust.go
index b8c8be5..05f6399 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -35,7 +35,7 @@
android.AddNeverAllowRules(
android.NeverAllow().
- NotIn(config.RustAllowedPaths...).
+ NotIn(append(config.RustAllowedPaths, config.DownstreamRustAllowedPaths...)...).
ModuleType(config.RustModuleTypes...))
android.RegisterModuleType("rust_defaults", defaultsFactory)
@@ -288,6 +288,10 @@
return mod.Properties.VndkVersion != ""
}
+func (mod *Module) Bootstrap() bool {
+ return false
+}
+
func (mod *Module) MustUseVendorVariant() bool {
return true
}
@@ -952,7 +956,7 @@
directRlibDeps := []*Module{}
directDylibDeps := []*Module{}
directProcMacroDeps := []*Module{}
- directSharedLibDeps := [](cc.LinkableInterface){}
+ directSharedLibDeps := []cc.SharedLibraryInfo{}
directStaticLibDeps := [](cc.LinkableInterface){}
directSrcProvidersDeps := []*Module{}
directSrcDeps := [](android.SourceFileProducer){}
@@ -1073,14 +1077,23 @@
directStaticLibDeps = append(directStaticLibDeps, ccDep)
mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, makeLibName)
case cc.IsSharedDepTag(depTag):
+ // For the shared lib dependencies, we may link to the stub variant
+ // of the dependency depending on the context (e.g. if this
+ // dependency crosses the APEX boundaries).
+ sharedLibraryInfo, exportedInfo := cc.ChooseStubOrImpl(ctx, dep)
+
+ // Re-get linkObject as ChooseStubOrImpl actually tells us which
+ // object (either from stub or non-stub) to use.
+ linkObject = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
+ linkPath = linkPathFromFilePath(linkObject.Path())
+
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
- exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
- directSharedLibDeps = append(directSharedLibDeps, ccDep)
+ directSharedLibDeps = append(directSharedLibDeps, sharedLibraryInfo)
// Record baseLibName for snapshots.
mod.Properties.SnapshotSharedLibs = append(mod.Properties.SnapshotSharedLibs, cc.BaseLibName(depName))
@@ -1135,11 +1148,11 @@
var sharedLibFiles android.Paths
var sharedLibDepFiles android.Paths
for _, dep := range directSharedLibDeps {
- sharedLibFiles = append(sharedLibFiles, dep.OutputFile().Path())
- if dep.Toc().Valid() {
- sharedLibDepFiles = append(sharedLibDepFiles, dep.Toc().Path())
+ sharedLibFiles = append(sharedLibFiles, dep.SharedLibrary)
+ if dep.TableOfContents.Valid() {
+ sharedLibDepFiles = append(sharedLibDepFiles, dep.TableOfContents.Path())
} else {
- sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
+ sharedLibDepFiles = append(sharedLibDepFiles, dep.SharedLibrary)
}
}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 1c02bd0..635be10 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -265,3 +265,19 @@
"linker_config_proto",
],
}
+
+python_binary_host {
+ name: "get_clang_version",
+ main: "get_clang_version.py",
+ srcs: [
+ "get_clang_version.py",
+ ],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ },
+ },
+}
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 2b9c2de..1830a18 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,6 +1,6 @@
per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
-per-file construct_context.py = ngeoffray@google.com,calin@google.com,mathieuc@google.com,skvadrik@google.com
+per-file construct_context.py = ngeoffray@google.com,calin@google.com,skvadrik@google.com
per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com
per-file gen_ndk*.sh = sophiez@google.com, allenhair@google.com
diff --git a/scripts/get_clang_version.py b/scripts/get_clang_version.py
new file mode 100755
index 0000000..622fca1
--- /dev/null
+++ b/scripts/get_clang_version.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# 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.
+"""A tool to report the current clang version used during build"""
+
+import os
+import re
+import sys
+
+
+ANDROID_BUILD_TOP = os.environ.get("ANDROID_BUILD_TOP", ".")
+
+def get_clang_prebuilts_version(global_go):
+ # TODO(b/187231324): Get clang version from the json file once it is no longer
+ # hard-coded in global.go
+ if global_go is None:
+ global_go = ANDROID_BUILD_TOP + '/build/soong/cc/config/global.go'
+ with open(global_go) as infile:
+ contents = infile.read()
+
+ regex_rev = r'\tClangDefaultVersion\s+= "clang-(?P<rev>r\d+[a-z]?\d?)"'
+ match_rev = re.search(regex_rev, contents)
+ if match_rev is None:
+ raise RuntimeError('Parsing clang info failed')
+ return match_rev.group('rev')
+
+
+def main():
+ global_go = sys.argv[1] if len(sys.argv) > 1 else None
+ print(get_clang_prebuilts_version(global_go));
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/get_clang_version_test.py b/scripts/get_clang_version_test.py
new file mode 100644
index 0000000..e57df6c
--- /dev/null
+++ b/scripts/get_clang_version_test.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+"""Unit tests for get_clang_version.py."""
+
+import unittest
+
+import get_clang_version
+
+class GetClangVersionTest(unittest.TestCase):
+ """Unit tests for get_clang_version."""
+
+ def test_get_clang_version(self):
+ """Test parsing of clang prebuilts version."""
+ self.assertIsNotNone(get_clang_version.get_clang_prebuilts_version())
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/scripts/hiddenapi/verify_overlaps.py b/scripts/hiddenapi/verify_overlaps.py
index c8e3879..bb0917e 100755
--- a/scripts/hiddenapi/verify_overlaps.py
+++ b/scripts/hiddenapi/verify_overlaps.py
@@ -47,9 +47,9 @@
if signature in allFlagsBySignature:
allFlags = allFlagsBySignature.get(signature)
if allFlags != row:
- mismatchingSignatures.append((signature, row[None], allFlags[None]))
+ mismatchingSignatures.append((signature, row.get(None, []), allFlags.get(None, [])))
else:
- mismatchingSignatures.append((signature, row[None], []))
+ mismatchingSignatures.append((signature, row.get(None, []), []))
if mismatchingSignatures:
@@ -60,7 +60,7 @@
for mismatch in mismatchingSignatures:
print()
print("< " + mismatch[0] + "," + ",".join(mismatch[1]))
- if mismatch[2] != None:
+ if mismatch[2] != []:
print("> " + mismatch[0] + "," + ",".join(mismatch[2]))
else:
print("> " + mismatch[0] + " - missing")
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 31555c0..98697dc 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -2189,7 +2189,7 @@
result := testSdkWithCc(t, `
sdk {
name: "mysdk",
- native_shared_libs: ["sslnil", "sslempty", "sslnonempty"],
+ native_shared_libs: ["sslnil", "sslempty", "sslnonempty", "dslnil", "dslempty", "dslnonempty"],
}
cc_library {
@@ -2206,6 +2206,21 @@
name: "sslnonempty",
system_shared_libs: ["sslnil"],
}
+
+ cc_library {
+ name: "dslnil",
+ host_supported: true,
+ }
+
+ cc_library {
+ name: "dslempty",
+ default_shared_libs: [],
+ }
+
+ cc_library {
+ name: "dslnonempty",
+ default_shared_libs: ["sslnil"],
+ }
`)
CheckSnapshot(t, result, "mysdk", "",
@@ -2261,13 +2276,62 @@
},
},
}
-`))
+
+cc_prebuilt_library_shared {
+ name: "dslnil",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ compile_multilib: "both",
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/dslnil.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/dslnil.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "dslempty",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ compile_multilib: "both",
+ default_shared_libs: [],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/dslempty.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/dslempty.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "dslnonempty",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ compile_multilib: "both",
+ default_shared_libs: ["sslnil"],
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/dslnonempty.so"],
+ },
+ arm: {
+ srcs: ["arm/lib/dslnonempty.so"],
+ },
+ },
+}`))
result = testSdkWithCc(t, `
sdk {
name: "mysdk",
host_supported: true,
- native_shared_libs: ["sslvariants"],
+ native_shared_libs: ["sslvariants", "dslvariants"],
}
cc_library {
@@ -2279,6 +2343,16 @@
},
},
}
+
+ cc_library {
+ name: "dslvariants",
+ host_supported: true,
+ target: {
+ android: {
+ default_shared_libs: [],
+ },
+ },
+ }
`)
CheckSnapshot(t, result, "mysdk", "",
@@ -2315,6 +2389,37 @@
},
},
}
+
+cc_prebuilt_library_shared {
+ name: "dslvariants",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ host_supported: true,
+ compile_multilib: "both",
+ target: {
+ host: {
+ enabled: false,
+ },
+ android: {
+ default_shared_libs: [],
+ },
+ android_arm64: {
+ srcs: ["android/arm64/lib/dslvariants.so"],
+ },
+ android_arm: {
+ srcs: ["android/arm/lib/dslvariants.so"],
+ },
+ linux_glibc_x86_64: {
+ enabled: true,
+ srcs: ["linux_glibc/x86_64/lib/dslvariants.so"],
+ },
+ linux_glibc_x86: {
+ enabled: true,
+ srcs: ["linux_glibc/x86/lib/dslvariants.so"],
+ },
+ },
+}
`),
checkVersionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2351,11 +2456,46 @@
},
}
+cc_prebuilt_library_shared {
+ name: "mysdk_dslvariants@current",
+ sdk_member_name: "dslvariants",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ host_supported: true,
+ installable: false,
+ compile_multilib: "both",
+ target: {
+ host: {
+ enabled: false,
+ },
+ android: {
+ default_shared_libs: [],
+ },
+ android_arm64: {
+ srcs: ["android/arm64/lib/dslvariants.so"],
+ },
+ android_arm: {
+ srcs: ["android/arm/lib/dslvariants.so"],
+ },
+ linux_glibc_x86_64: {
+ enabled: true,
+ srcs: ["linux_glibc/x86_64/lib/dslvariants.so"],
+ },
+ linux_glibc_x86: {
+ enabled: true,
+ srcs: ["linux_glibc/x86/lib/dslvariants.so"],
+ },
+ },
+}
+
sdk_snapshot {
name: "mysdk@current",
visibility: ["//visibility:public"],
host_supported: true,
- native_shared_libs: ["mysdk_sslvariants@current"],
+ native_shared_libs: [
+ "mysdk_sslvariants@current",
+ "mysdk_dslvariants@current",
+ ],
target: {
host: {
enabled: false,
diff --git a/sdk/update.go b/sdk/update.go
index 3f61339..b146b62 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -156,6 +156,11 @@
if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
memberType := memberTag.SdkMemberType(child)
+ // If a nil SdkMemberType was returned then this module should not be added to the sdk.
+ if memberType == nil {
+ return false
+ }
+
// Make sure that the resolved module is allowed in the member list property.
if !memberType.IsInstance(child) {
ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 8c8dc82..1258684 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -486,6 +486,39 @@
fi
}
+function test_write_to_source_tree {
+ setup
+ mkdir -p a
+ cat > a/Android.bp <<EOF
+genrule {
+ name: "write_to_source_tree",
+ out: ["write_to_source_tree"],
+ cmd: "touch file_in_source_tree && touch \$(out)",
+}
+EOF
+ readonly EXPECTED_OUT=out/soong/.intermediates/a/write_to_source_tree/gen/write_to_source_tree
+ readonly ERROR_LOG=${MOCK_TOP}/out/error.log
+ readonly ERROR_MSG="Read-only file system"
+ readonly ERROR_HINT_PATTERN="BUILD_BROKEN_SRC_DIR"
+ # Test in ReadOnly source tree
+ run_ninja BUILD_BROKEN_SRC_DIR_IS_WRITABLE=false ${EXPECTED_OUT} &> /dev/null && \
+ fail "Write to source tree should not work in a ReadOnly source tree"
+
+ if grep -q "${ERROR_MSG}" ${ERROR_LOG} && grep -q "${ERROR_HINT_PATTERN}" ${ERROR_LOG} ; then
+ echo Error message and error hint found in logs >/dev/null
+ else
+ fail "Did not find Read-only error AND error hint in error.log"
+ fi
+
+ # Test in ReadWrite source tree
+ run_ninja BUILD_BROKEN_SRC_DIR_IS_WRITABLE=true ${EXPECTED_OUT} &> /dev/null || \
+ fail "Write to source tree did not succeed in a ReadWrite source tree"
+
+ if grep -q "${ERROR_MSG}\|${ERROR_HINT_PATTERN}" ${ERROR_LOG} ; then
+ fail "Found read-only error OR error hint in error.log"
+ fi
+}
+
function test_bp2build_smoke {
setup
GENERATE_BAZEL_FILES=1 run_soong
@@ -692,6 +725,7 @@
test_glob_during_bootstrapping
test_soong_build_rerun_iff_environment_changes
test_dump_json_module_graph
+test_write_to_source_tree
test_bp2build_smoke
test_bp2build_generates_fake_ninja_file
test_bp2build_null_build
diff --git a/tests/lib.sh b/tests/lib.sh
index 35ccea9..f1e1efa 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -126,6 +126,10 @@
GENERATE_BAZEL_FILES=true build/soong/soong_ui.bash --make-mode --skip-ninja --skip-make --skip-soong-tests nothing
}
+run_ninja() {
+ build/soong/soong_ui.bash --make-mode --skip-make --skip-soong-tests "$@"
+}
+
info "Starting Soong integration test suite $(basename $0)"
info "Mock top: $MOCK_TOP"
diff --git a/ui/build/build.go b/ui/build/build.go
index 1187aa2..1ed9014 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -28,16 +28,20 @@
func SetupOutDir(ctx Context, config Config) {
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk"))
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
- if !config.SkipKati() {
- // Run soong_build with Kati for a hybrid build, e.g. running the
- // AndroidMk singleton and postinstall commands. Communicate this to
- // soong_build by writing an empty .soong.kati_enabled marker file in the
- // soong_build output directory for the soong_build primary builder to
- // know if the user wants to run Kati after.
- //
- // This does not preclude running Kati for *product configuration purposes*.
- ensureEmptyFileExists(ctx, filepath.Join(config.SoongOutDir(), ".soong.kati_enabled"))
+
+ // Potentially write a marker file for whether kati is enabled. This is used by soong_build to
+ // potentially run the AndroidMk singleton and postinstall commands.
+ // Note that the absence of the file does not not preclude running Kati for product
+ // configuration purposes.
+ katiEnabledMarker := filepath.Join(config.SoongOutDir(), ".soong.kati_enabled")
+ if config.SkipKatiNinja() {
+ os.Remove(katiEnabledMarker)
+ // Note that we can not remove the file for SkipKati builds yet -- some continuous builds
+ // --skip-make builds rely on kati targets being defined.
+ } else if !config.SkipKati() {
+ ensureEmptyFileExists(ctx, katiEnabledMarker)
}
+
// The ninja_build file is used by our buildbots to understand that the output
// can be parsed as ninja output.
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
diff --git a/ui/build/config.go b/ui/build/config.go
index 4806721..7370627 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -161,6 +161,10 @@
ret.distDir = filepath.Join(ret.OutDir(), "dist")
}
+ if srcDirIsWritable, ok := ret.environ.Get("BUILD_BROKEN_SRC_DIR_IS_WRITABLE"); ok {
+ ret.sandboxConfig.SetSrcDirIsRO(srcDirIsWritable == "false")
+ }
+
ret.environ.Unset(
// We're already using it
"USE_SOONG_UI",
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index b0a6748..5b2046e 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -97,8 +97,11 @@
"-u", "nobody",
"-g", sandboxConfig.group,
"-R", "/",
- "-B", sandboxConfig.srcDir,
+ // Mount tmp before srcDir
+ // srcDir is /tmp/.* in integration tests, which is a child dir of /tmp
+ // nsjail throws an error if a child dir is mounted before its parent
"-B", "/tmp",
+ "-B", sandboxConfig.srcDir,
"-B", sandboxConfig.outDir,
}
diff --git a/ui/status/ninja.go b/ui/status/ninja.go
index 765679f..2445972 100644
--- a/ui/status/ninja.go
+++ b/ui/status/ninja.go
@@ -19,6 +19,8 @@
"fmt"
"io"
"os"
+ "regexp"
+ "strings"
"syscall"
"time"
@@ -158,9 +160,10 @@
err = fmt.Errorf("exited with code: %d", exitCode)
}
+ outputWithErrorHint := errorHintGenerator.GetOutputWithErrorHint(msg.EdgeFinished.GetOutput(), exitCode)
n.status.FinishAction(ActionResult{
Action: started,
- Output: msg.EdgeFinished.GetOutput(),
+ Output: outputWithErrorHint,
Error: err,
Stats: ActionResultStats{
UserTime: msg.EdgeFinished.GetUserTime(),
@@ -219,3 +222,53 @@
return ret, nil
}
+
+// key is pattern in stdout/stderr
+// value is error hint
+var allErrorHints = map[string]string{
+ "Read-only file system": `\nWrite to a read-only file system detected. Possible fixes include
+1. Generate file directly to out/ which is ReadWrite, #recommend solution
+2. BUILD_BROKEN_SRC_DIR_RW_ALLOWLIST := <my/path/1> <my/path/2> #discouraged, subset of source tree will be RW
+3. BUILD_BROKEN_SRC_DIR_IS_WRITABLE := true #highly discouraged, entire source tree will be RW
+`,
+}
+var errorHintGenerator = *newErrorHintGenerator(allErrorHints)
+
+type ErrorHintGenerator struct {
+ allErrorHints map[string]string
+ allErrorHintPatternsCompiled *regexp.Regexp
+}
+
+func newErrorHintGenerator(allErrorHints map[string]string) *ErrorHintGenerator {
+ var allErrorHintPatterns []string
+ for errorHintPattern, _ := range allErrorHints {
+ allErrorHintPatterns = append(allErrorHintPatterns, errorHintPattern)
+ }
+ allErrorHintPatternsRegex := strings.Join(allErrorHintPatterns[:], "|")
+ re := regexp.MustCompile(allErrorHintPatternsRegex)
+ return &ErrorHintGenerator{
+ allErrorHints: allErrorHints,
+ allErrorHintPatternsCompiled: re,
+ }
+}
+
+func (errorHintGenerator *ErrorHintGenerator) GetOutputWithErrorHint(rawOutput string, buildExitCode int) string {
+ if buildExitCode == 0 {
+ return rawOutput
+ }
+ errorHint := errorHintGenerator.getErrorHint(rawOutput)
+ if errorHint == nil {
+ return rawOutput
+ }
+ return rawOutput + *errorHint
+}
+
+// Returns the error hint corresponding to the FIRST match in raw output
+func (errorHintGenerator *ErrorHintGenerator) getErrorHint(rawOutput string) *string {
+ firstMatch := errorHintGenerator.allErrorHintPatternsCompiled.FindString(rawOutput)
+ if _, found := errorHintGenerator.allErrorHints[firstMatch]; found {
+ errorHint := errorHintGenerator.allErrorHints[firstMatch]
+ return &errorHint
+ }
+ return nil
+}
diff --git a/ui/status/ninja_test.go b/ui/status/ninja_test.go
index c400c97..f3638b3 100644
--- a/ui/status/ninja_test.go
+++ b/ui/status/ninja_test.go
@@ -43,3 +43,53 @@
t.Errorf("nr.Close timed out, %s > %s", g, w)
}
}
+
+// Test that error hint is added to output if available
+func TestNinjaReader_CorrectErrorHint(t *testing.T) {
+ errorPattern1 := "pattern-1 in input"
+ errorHint1 := "\n Fix by doing task 1"
+ errorPattern2 := "pattern-2 in input"
+ errorHint2 := "\n Fix by doing task 2"
+ mockErrorHints := make(map[string]string)
+ mockErrorHints[errorPattern1] = errorHint1
+ mockErrorHints[errorPattern2] = errorHint2
+
+ errorHintGenerator := *newErrorHintGenerator(mockErrorHints)
+ testCases := []struct {
+ rawOutput string
+ buildExitCode int
+ expectedFinalOutput string
+ testCaseErrorMessage string
+ }{
+ {
+ rawOutput: "ninja build was successful",
+ buildExitCode: 0,
+ expectedFinalOutput: "ninja build was successful",
+ testCaseErrorMessage: "raw output changed when build was successful",
+ },
+ {
+ rawOutput: "ninja build failed",
+ buildExitCode: 1,
+ expectedFinalOutput: "ninja build failed",
+ testCaseErrorMessage: "raw output changed even when no error hint pattern was found",
+ },
+ {
+ rawOutput: "ninja build failed: " + errorPattern1 + "some footnotes",
+ buildExitCode: 1,
+ expectedFinalOutput: "ninja build failed: " + errorPattern1 + "some footnotes" + errorHint1,
+ testCaseErrorMessage: "error hint not added despite pattern match",
+ },
+ {
+ rawOutput: "ninja build failed: " + errorPattern2 + errorPattern1,
+ buildExitCode: 1,
+ expectedFinalOutput: "ninja build failed: " + errorPattern2 + errorPattern1 + errorHint2,
+ testCaseErrorMessage: "error hint should be added for first pattern match in raw output",
+ },
+ }
+ for _, testCase := range testCases {
+ actualFinalOutput := errorHintGenerator.GetOutputWithErrorHint(testCase.rawOutput, testCase.buildExitCode)
+ if actualFinalOutput != testCase.expectedFinalOutput {
+ t.Errorf(testCase.testCaseErrorMessage+"\nexpected: %s\ngot: %s", testCase.expectedFinalOutput, actualFinalOutput)
+ }
+ }
+}