Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e223512b authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Prebuilt stub not available to platform is handled correctly"

parents c7dff7f1 f7c3bbe4
Loading
Loading
Loading
Loading
+14 −10
Original line number Diff line number Diff line
@@ -153,13 +153,12 @@ type ApexModule interface {
	// 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 @@ type ApexProperties struct {
	// 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 @@ func (m *ApexModuleBase) DirectlyInAnyApex() bool {
}

// 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
+155 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
package apex

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
@@ -6411,6 +6412,160 @@ func TestExcludeDependency(t *testing.T) {
	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()
+8 −3
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ type AndroidMkContext interface {
	InRamdisk() bool
	InVendorRamdisk() bool
	InRecovery() bool
	AnyVariantDirectlyInAnyApex() bool
	NotInPlatform() bool
}

type subAndroidMkProvider interface {
@@ -281,10 +281,15 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries
			}
		})
	}
	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() {
+9 −8
Original line number Diff line number Diff line
@@ -1586,13 +1586,14 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
		}
		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 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
						// 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.