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

Commit 127b40b3 authored by Jiyong Park's avatar Jiyong Park
Browse files

Add apex_available to control the availablity of a module to APEXes

apex_available property controls the availability of a module to APEXes.
For example, `apex_available: ["myapex", "otherapex"]` makes the module
available only to the two APEXes: myapex and otherapex, and nothing
else, even to the platform.

If the module is intended to be available to any APEX, then a pseudo
name "//apex_available:anyapex" can be used.

If the module is intended to be available to the platform, then another
pseudo name "//apex_available:platform" is used.

For now, if unspecified, this property defaults to ["//apex_available:platform",
"//apex_available:anyapex"], which means the module is available to everybody.
This will be reduced to ["//apex_available:platform"], when marking for
apex_available for existing modules are finished.

Bug: 139870423
Bug: 128708192
Test: m
Change-Id: Id4b233c3056c7858f984cbf9427cfac4118b2682
parent fdc9afa1
Loading
Loading
Loading
Loading
+44 −2
Original line number Diff line number Diff line
@@ -78,12 +78,23 @@ type ApexModule interface {

	// Return the no_apex property
	NoApex() bool

	// Tests if this module is available for the specified APEX or ":platform"
	AvailableFor(what string) bool
}

type ApexProperties struct {
	// Whether this module should not be part of any APEX. Default is false.
	// TODO(b/128708192): remove this as this is equal to apex_available: [":platform"]
	No_apex *bool

	// Availability of this module in APEXes. Only the listed APEXes can include this module.
	// "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
	// "//apex_available:platform" refers to non-APEX partitions like "system.img".
	// Default is ["//apex_available:platform", "//apex_available:anyapex"].
	// TODO(b/128708192) change the default to ["//apex_available:platform"]
	Apex_available []string

	// Name of the apex variant that this module is mutated into
	ApexName string `blueprint:"mutated"`
}
@@ -136,15 +147,46 @@ func (m *ApexModuleBase) NoApex() bool {
	return proptools.Bool(m.ApexProperties.No_apex)
}

const (
	availableToPlatform = "//apex_available:platform"
	availableToAnyApex  = "//apex_available:anyapex"
)

func (m *ApexModuleBase) AvailableFor(what string) bool {
	if len(m.ApexProperties.Apex_available) == 0 {
		// apex_available defaults to ["//apex_available:platform", "//apex_available:anyapex"],
		// which means 'available to everybody'.
		return true
	}
	return InList(what, m.ApexProperties.Apex_available) ||
		(what != availableToPlatform && InList(availableToAnyApex, m.ApexProperties.Apex_available))
}

func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
	for _, n := range m.ApexProperties.Apex_available {
		if n == availableToPlatform || n == availableToAnyApex {
			continue
		}
		if !mctx.OtherModuleExists(n) {
			mctx.PropertyErrorf("apex_available", "%q is not a valid module name", n)
		}
	}
}

func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []blueprint.Module {
	if len(m.apexVariations) > 0 {
		m.checkApexAvailableProperty(mctx)
		sort.Strings(m.apexVariations)
		variations := []string{""} // Original variation for platform
		variations := []string{}
		availableForPlatform := m.AvailableFor(availableToPlatform)
		if availableForPlatform {
			variations = append(variations, "") // Original variation for platform
		}
		variations = append(variations, m.apexVariations...)

		modules := mctx.CreateVariations(variations...)
		for i, m := range modules {
			if i == 0 {
			if availableForPlatform && i == 0 {
				continue
			}
			m.(ApexModule).setApexName(variations[i])
+10 −0
Original line number Diff line number Diff line
@@ -1215,6 +1215,16 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
		}
	}

	// check apex_available requirements
	for _, fi := range filesInfo {
		if am, ok := fi.module.(android.ApexModule); ok {
			if !am.AvailableFor(ctx.ModuleName()) {
				ctx.ModuleErrorf("requires %q that is not available for the APEX", fi.module.Name())
				return
			}
		}
	}

	// prepend the name of this APEX to the module names. These names will be the names of
	// modules that will be defined if the APEX is flattened.
	for i := range filesInfo {
+152 −0
Original line number Diff line number Diff line
@@ -2422,6 +2422,158 @@ func TestApexWithApps(t *testing.T) {

}

func TestApexAvailable(t *testing.T) {
	// libfoo is not available to myapex, but only to otherapex
	testApexError(t, "requires \"libfoo\" that is not available for the APEX", `
	apex {
		name: "myapex",
		key: "myapex.key",
		native_shared_libs: ["libfoo"],
	}

	apex_key {
		name: "myapex.key",
		public_key: "testkey.avbpubkey",
		private_key: "testkey.pem",
	}

	apex {
		name: "otherapex",
		key: "otherapex.key",
		native_shared_libs: ["libfoo"],
	}

	apex_key {
		name: "otherapex.key",
		public_key: "testkey.avbpubkey",
		private_key: "testkey.pem",
	}

	cc_library {
		name: "libfoo",
		stl: "none",
		system_shared_libs: [],
		apex_available: ["otherapex"],
	}`)

	// libbar is an indirect dep
	testApexError(t, "requires \"libbar\" that is not available for the APEX", `
	apex {
		name: "myapex",
		key: "myapex.key",
		native_shared_libs: ["libfoo"],
	}

	apex_key {
		name: "myapex.key",
		public_key: "testkey.avbpubkey",
		private_key: "testkey.pem",
	}

	apex {
		name: "otherapex",
		key: "otherapex.key",
		native_shared_libs: ["libfoo"],
	}

	apex_key {
		name: "otherapex.key",
		public_key: "testkey.avbpubkey",
		private_key: "testkey.pem",
	}

	cc_library {
		name: "libfoo",
		stl: "none",
		shared_libs: ["libbar"],
		system_shared_libs: [],
		apex_available: ["myapex", "otherapex"],
	}

	cc_library {
		name: "libbar",
		stl: "none",
		system_shared_libs: [],
		apex_available: ["otherapex"],
	}`)

	testApexError(t, "\"otherapex\" is not a valid module name", `
	apex {
		name: "myapex",
		key: "myapex.key",
		native_shared_libs: ["libfoo"],
	}

	apex_key {
		name: "myapex.key",
		public_key: "testkey.avbpubkey",
		private_key: "testkey.pem",
	}

	cc_library {
		name: "libfoo",
		stl: "none",
		system_shared_libs: [],
		apex_available: ["otherapex"],
	}`)

	ctx, _ := testApex(t, `
	apex {
		name: "myapex",
		key: "myapex.key",
		native_shared_libs: ["libfoo", "libbar"],
	}

	apex_key {
		name: "myapex.key",
		public_key: "testkey.avbpubkey",
		private_key: "testkey.pem",
	}

	cc_library {
		name: "libfoo",
		stl: "none",
		system_shared_libs: [],
		apex_available: ["myapex"],
	}

	cc_library {
		name: "libbar",
		stl: "none",
		system_shared_libs: [],
		apex_available: ["//apex_available:anyapex"],
	}`)

	// check that libfoo and libbar are created only for myapex, but not for the platform
	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex")
	ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared")
	ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_core_shared_myapex")
	ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_core_shared")

	ctx, _ = testApex(t, `
	apex {
		name: "myapex",
		key: "myapex.key",
	}

	apex_key {
		name: "myapex.key",
		public_key: "testkey.avbpubkey",
		private_key: "testkey.pem",
	}

	cc_library {
		name: "libfoo",
		stl: "none",
		system_shared_libs: [],
		apex_available: ["//apex_available:platform"],
	}`)

	// check that libfoo is created only for the platform
	ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared_myapex")
	ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_core_shared")
}

func TestMain(m *testing.M) {
	run := func() int {
		setUp()