Merge "Prebuilt stub not available to platform is handled correctly"
diff --git a/android/apex.go b/android/apex.go
index 4a71b40..f6eca86 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -153,13 +153,12 @@
// run.
DirectlyInAnyApex() bool
- // Returns true in the primary variant of a module if _any_ variant of the module is
- // directly in any apex. This includes host, arch, asan, etc. variants. It is unused in any
- // variant that is not the primary variant. Ideally this wouldn't be used, as it incorrectly
- // mixes arch variants if only one arch is in an apex, but a few places depend on it, for
- // example when an ASAN variant is created before the apexMutator. Call this after
- // apex.apexMutator is run.
- AnyVariantDirectlyInAnyApex() bool
+ // NotInPlatform tells whether or not this module is included in an APEX and therefore
+ // shouldn't be exposed to the platform (i.e. outside of the APEX) directly. A module is
+ // considered to be included in an APEX either when there actually is an APEX that
+ // explicitly has the module as its dependency or the module is not available to the
+ // platform, which indicates that the module belongs to at least one or more other APEXes.
+ NotInPlatform() bool
// Tests if this module could have APEX variants. Even when a module type implements
// ApexModule interface, APEX variants are created only for the module instances that return
@@ -221,7 +220,12 @@
// See ApexModule.DirectlyInAnyApex()
DirectlyInAnyApex bool `blueprint:"mutated"`
- // See ApexModule.AnyVariantDirectlyInAnyApex()
+ // AnyVariantDirectlyInAnyApex is true in the primary variant of a module if _any_ variant
+ // of the module is directly in any apex. This includes host, arch, asan, etc. variants. It
+ // is unused in any variant that is not the primary variant. Ideally this wouldn't be used,
+ // as it incorrectly mixes arch variants if only one arch is in an apex, but a few places
+ // depend on it, for example when an ASAN variant is created before the apexMutator. Call
+ // this after apex.apexMutator is run.
AnyVariantDirectlyInAnyApex bool `blueprint:"mutated"`
// See ApexModule.NotAvailableForPlatform()
@@ -302,8 +306,8 @@
}
// Implements ApexModule
-func (m *ApexModuleBase) AnyVariantDirectlyInAnyApex() bool {
- return m.ApexProperties.AnyVariantDirectlyInAnyApex
+func (m *ApexModuleBase) NotInPlatform() bool {
+ return m.ApexProperties.AnyVariantDirectlyInAnyApex || !m.AvailableFor(AvailableToPlatform)
}
// Implements ApexModule
diff --git a/apex/apex_test.go b/apex/apex_test.go
index ab8ae16..f71e7ef 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -15,6 +15,7 @@
package apex
import (
+ "fmt"
"io/ioutil"
"os"
"path"
@@ -6411,6 +6412,160 @@
ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
}
+func TestPrebuiltStubLibDep(t *testing.T) {
+ bpBase := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ apex_available: ["myapex"],
+ shared_libs: ["stublib"],
+ system_shared_libs: [],
+ }
+ apex {
+ name: "otherapex",
+ enabled: %s,
+ key: "myapex.key",
+ native_shared_libs: ["stublib"],
+ }
+ `
+
+ stublibSourceBp := `
+ cc_library {
+ name: "stublib",
+ srcs: ["mylib.cpp"],
+ apex_available: ["otherapex"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1"],
+ },
+ }
+ `
+
+ stublibPrebuiltBp := `
+ cc_prebuilt_library_shared {
+ name: "stublib",
+ srcs: ["prebuilt.so"],
+ apex_available: ["otherapex"],
+ stubs: {
+ versions: ["1"],
+ },
+ %s
+ }
+ `
+
+ tests := []struct {
+ name string
+ stublibBp string
+ usePrebuilt bool
+ modNames []string // Modules to collect AndroidMkEntries for
+ otherApexEnabled []string
+ }{
+ {
+ name: "only_source",
+ stublibBp: stublibSourceBp,
+ usePrebuilt: false,
+ modNames: []string{"stublib"},
+ otherApexEnabled: []string{"true", "false"},
+ },
+ {
+ name: "source_preferred",
+ stublibBp: stublibSourceBp + fmt.Sprintf(stublibPrebuiltBp, ""),
+ usePrebuilt: false,
+ modNames: []string{"stublib", "prebuilt_stublib"},
+ otherApexEnabled: []string{"true", "false"},
+ },
+ {
+ name: "prebuilt_preferred",
+ stublibBp: stublibSourceBp + fmt.Sprintf(stublibPrebuiltBp, "prefer: true,"),
+ usePrebuilt: true,
+ modNames: []string{"stublib", "prebuilt_stublib"},
+ otherApexEnabled: []string{"false"}, // No "true" since APEX cannot depend on prebuilt.
+ },
+ {
+ name: "only_prebuilt",
+ stublibBp: fmt.Sprintf(stublibPrebuiltBp, ""),
+ usePrebuilt: true,
+ modNames: []string{"stublib"},
+ otherApexEnabled: []string{"false"}, // No "true" since APEX cannot depend on prebuilt.
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ for _, otherApexEnabled := range test.otherApexEnabled {
+ t.Run("otherapex_enabled_"+otherApexEnabled, func(t *testing.T) {
+ ctx, config := testApex(t, fmt.Sprintf(bpBase, otherApexEnabled)+test.stublibBp)
+
+ type modAndMkEntries struct {
+ mod *cc.Module
+ mkEntries android.AndroidMkEntries
+ }
+ entries := []*modAndMkEntries{}
+
+ // Gather shared lib modules that are installable
+ for _, modName := range test.modNames {
+ for _, variant := range ctx.ModuleVariantsForTests(modName) {
+ if !strings.HasPrefix(variant, "android_arm64_armv8-a_shared") {
+ continue
+ }
+ mod := ctx.ModuleForTests(modName, variant).Module().(*cc.Module)
+ if !mod.Enabled() || mod.IsSkipInstall() {
+ continue
+ }
+ for _, ent := range android.AndroidMkEntriesForTest(t, config, "", mod) {
+ if ent.Disabled {
+ continue
+ }
+ entries = append(entries, &modAndMkEntries{
+ mod: mod,
+ mkEntries: ent,
+ })
+ }
+ }
+ }
+
+ var entry *modAndMkEntries = nil
+ for _, ent := range entries {
+ if strings.Join(ent.mkEntries.EntryMap["LOCAL_MODULE"], ",") == "stublib" {
+ if entry != nil {
+ t.Errorf("More than one AndroidMk entry for \"stublib\": %s and %s", entry.mod, ent.mod)
+ } else {
+ entry = ent
+ }
+ }
+ }
+
+ if entry == nil {
+ t.Errorf("AndroidMk entry for \"stublib\" missing")
+ } else {
+ isPrebuilt := entry.mod.Prebuilt() != nil
+ if isPrebuilt != test.usePrebuilt {
+ t.Errorf("Wrong module for \"stublib\" AndroidMk entry: got prebuilt %t, want prebuilt %t", isPrebuilt, test.usePrebuilt)
+ }
+ if !entry.mod.IsStubs() {
+ t.Errorf("Module for \"stublib\" AndroidMk entry isn't a stub: %s", entry.mod)
+ }
+ if entry.mkEntries.EntryMap["LOCAL_NOT_AVAILABLE_FOR_PLATFORM"] != nil {
+ t.Errorf("AndroidMk entry for \"stublib\" has LOCAL_NOT_AVAILABLE_FOR_PLATFORM set: %+v", entry.mkEntries)
+ }
+ }
+ })
+ }
+ })
+ }
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 4f4b047..187a2ff 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -46,7 +46,7 @@
InRamdisk() bool
InVendorRamdisk() bool
InRecovery() bool
- AnyVariantDirectlyInAnyApex() bool
+ NotInPlatform() bool
}
type subAndroidMkProvider interface {
@@ -281,10 +281,15 @@
}
})
}
- if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.AnyVariantDirectlyInAnyApex() &&
+ // If a library providing a stub is included in an APEX, the private APIs of the library
+ // is accessible only inside the APEX. From outside of the APEX, clients can only use the
+ // public APIs via the stub. To enforce this, the (latest version of the) stub gets the
+ // name of the library. The impl library instead gets the `.bootstrap` suffix to so that
+ // they can be exceptionally used directly when APEXes are not available (e.g. during the
+ // very early stage in the boot process).
+ if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.NotInPlatform() &&
!ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() && !ctx.static() {
if library.buildStubs() && library.isLatestStubVersion() {
- // reference the latest version via its name without suffix when it is provided by apex
entries.SubName = ""
}
if !library.buildStubs() {
diff --git a/cc/cc.go b/cc/cc.go
index d1f5c47..afdf85b 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1586,13 +1586,14 @@
}
c.outputFile = android.OptionalPathForPath(outputFile)
- // If a lib is directly included in any of the APEXes, unhide the stubs
- // variant having the latest version gets visible to make. In addition,
- // the non-stubs variant is renamed to <libname>.bootstrap. This is to
- // force anything in the make world to link against the stubs library.
- // (unless it is explicitly referenced via .bootstrap suffix or the
- // module is marked with 'bootstrap: true').
- if c.HasStubsVariants() && c.AnyVariantDirectlyInAnyApex() && !c.InRamdisk() &&
+ // If a lib is directly included in any of the APEXes or is not available to the
+ // platform (which is often the case when the stub is provided as a prebuilt),
+ // unhide the stubs variant having the latest version gets visible to make. In
+ // addition, the non-stubs variant is renamed to <libname>.bootstrap. This is to
+ // force anything in the make world to link against the stubs library. (unless it
+ // is explicitly referenced via .bootstrap suffix or the module is marked with
+ // 'bootstrap: true').
+ if c.HasStubsVariants() && c.NotInPlatform() && !c.InRamdisk() &&
!c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
c.IsStubs() && !c.InVendorRamdisk() {
c.Properties.HideFromMake = false // unhide
@@ -2472,7 +2473,7 @@
// 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).AnyVariantDirectlyInAnyApex() && !c.bootstrap()
+ useStubs = dep.(android.ApexModule).NotInPlatform() && !c.bootstrap()
// Another exception: if this module is bundled with 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.