Support VNDK extensions
This commit adds `extends: "name"` property and provides basic support
to VNDK extensions. This is the simplest example:
```
cc_library {
name: "libvndk",
vendor_available: true,
vndk {
enabled: true,
},
}
cc_library {
name: "libvndk_ext",
vendor: true,
vndk: {
enabled: true,
extends: "libvndk",
},
}
```
A vndk extension library must extend an existing vndk library which has
`vendor_available: true`. These two libraries must have the same
`support_system_process` property.
VNDK-ext libraries are installed to `/vendor/lib[64]/vndk` and
VNDK-SP-ext libraries are installed to `/vendor/lib[64]/vndk-sp` by
default.
If there is a matching abi-dumps in `prebuilts/abi-dumps`,
`header-abi-diff` will be invoked to check for ABI breakages.
Bug: 38340960
Test: lunch aosp_walleye-userdebug && make -j8 # runs unit tests
Test: lunch aosp_arm-userdebug && make -j8 # build a target w/o VNDK
Test: Create a lsdump for a vndk lib, add an exported API to vndk lib,
and build fails as expected.
Test: Create a lsdump for a vndk lib, create an vndk extension lib with
extra API, and build succeeds as expected.
Test: Create libutils_ext, add an extra function to libutils_ext, and
call it from a HIDL service.
Change-Id: Iba90e08848ee99814405457f047321e6b52b2df0
diff --git a/cc/cc.go b/cc/cc.go
index a3af304..9b1f220 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -205,9 +205,11 @@
useVndk() bool
isVndk() bool
isVndkSp() bool
+ isVndkExt() bool
createVndkSourceAbiDump() bool
selectedStl() string
baseModuleName() string
+ getVndkExtendsModuleName() string
}
type ModuleContext interface {
@@ -289,6 +291,7 @@
reuseObjTag = dependencyTag{name: "reuse objects"}
ndkStubDepTag = dependencyTag{name: "ndk stub", library: true}
ndkLateStubDepTag = dependencyTag{name: "ndk late stub", library: true}
+ vndkExtDepTag = dependencyTag{name: "vndk extends", library: true}
)
// Module contains the properties and members used by all C/C++ module types, and implements
@@ -398,12 +401,33 @@
}
func (c *Module) isVndk() bool {
- if c.vndkdep != nil {
- return c.vndkdep.isVndk()
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.isVndk()
}
return false
}
+func (c *Module) isVndkSp() bool {
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.isVndkSp()
+ }
+ return false
+}
+
+func (c *Module) isVndkExt() bool {
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.isVndkExt()
+ }
+ return false
+}
+
+func (c *Module) getVndkExtendsModuleName() string {
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.getVndkExtendsModuleName()
+ }
+ return ""
+}
+
// Returns true only when this module is configured to have core and vendor
// variants.
func (c *Module) hasVendorVariant() bool {
@@ -474,18 +498,20 @@
return ""
}
-func (ctx *moduleContextImpl) isVndk() bool {
- return ctx.mod.isVndk()
-}
func (ctx *moduleContextImpl) useVndk() bool {
return ctx.mod.useVndk()
}
+func (ctx *moduleContextImpl) isVndk() bool {
+ return ctx.mod.isVndk()
+}
+
func (ctx *moduleContextImpl) isVndkSp() bool {
- if vndk := ctx.mod.vndkdep; vndk != nil {
- return vndk.isVndkSp()
- }
- return false
+ return ctx.mod.isVndkSp()
+}
+
+func (ctx *moduleContextImpl) isVndkExt() bool {
+ return ctx.mod.isVndkExt()
}
// Create source abi dumps if the module belongs to the list of VndkLibraries.
@@ -504,6 +530,10 @@
return ctx.mod.ModuleBase.BaseModuleName()
}
+func (ctx *moduleContextImpl) getVndkExtendsModuleName() string {
+ return ctx.mod.getVndkExtendsModuleName()
+}
+
func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
return &Module{
hod: hod,
@@ -935,6 +965,18 @@
{"ndk_api", version}, {"link", "shared"}}, ndkStubDepTag, variantNdkLibs...)
actx.AddVariationDependencies([]blueprint.Variation{
{"ndk_api", version}, {"link", "shared"}}, ndkLateStubDepTag, variantLateNdkLibs...)
+
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ if vndkdep.isVndkExt() {
+ baseModuleMode := vendorMode
+ if actx.DeviceConfig().VndkVersion() == "" {
+ baseModuleMode = coreMode
+ }
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {"image", baseModuleMode}, {"link", "shared"}}, vndkExtDepTag,
+ vndkdep.getVndkExtendsModuleName())
+ }
+ }
}
func beginMutator(ctx android.BottomUpMutatorContext) {
@@ -959,7 +1001,7 @@
// Whether a module can link to another module, taking into
// account NDK linking.
-func checkLinkType(ctx android.ModuleContext, from *Module, to *Module) {
+func checkLinkType(ctx android.ModuleContext, from *Module, to *Module, tag dependencyTag) {
if from.Target().Os != android.Android {
// Host code is not restricted
return
@@ -969,7 +1011,7 @@
// each vendor-available module needs to check
// link-type for VNDK.
if from.vndkdep != nil {
- from.vndkdep.vndkCheckLinkType(ctx, to)
+ from.vndkdep.vndkCheckLinkType(ctx, to, tag)
}
return
}
@@ -1151,7 +1193,7 @@
}
}
- checkLinkType(ctx, c, ccDep)
+ checkLinkType(ctx, c, ccDep, t)
}
var ptr *android.Paths
@@ -1411,21 +1453,47 @@
}
// Sanity check
- if m.VendorProperties.Vendor_available != nil && (mctx.SocSpecific() || mctx.DeviceSpecific()) {
+ vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
+
+ if m.VendorProperties.Vendor_available != nil && vendorSpecific {
mctx.PropertyErrorf("vendor_available",
"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
return
}
- if vndk := m.vndkdep; vndk != nil {
- if vndk.isVndk() && m.VendorProperties.Vendor_available == nil {
- mctx.PropertyErrorf("vndk",
- "vendor_available must be set to either true or false when `vndk: {enabled: true}`")
- return
- }
- if !vndk.isVndk() && vndk.isVndkSp() {
- mctx.PropertyErrorf("vndk",
- "must set `enabled: true` to set `support_system_process: true`")
- return
+
+ if vndkdep := m.vndkdep; vndkdep != nil {
+ if vndkdep.isVndk() {
+ if vendorSpecific {
+ if !vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `extends: \"...\"` to vndk extension")
+ return
+ }
+ } else {
+ if vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `vendor: true` to set `extends: %q`",
+ m.getVndkExtendsModuleName())
+ return
+ }
+ if m.VendorProperties.Vendor_available == nil {
+ mctx.PropertyErrorf("vndk",
+ "vendor_available must be set to either true or false when `vndk: {enabled: true}`")
+ return
+ }
+ }
+ } else {
+ if vndkdep.isVndkSp() {
+ mctx.PropertyErrorf("vndk",
+ "must set `enabled: true` to set `support_system_process: true`")
+ return
+ }
+ if vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `enabled: true` to set `extends: %q`",
+ m.getVndkExtendsModuleName())
+ return
+ }
}
}
@@ -1453,14 +1521,14 @@
vendor.Properties.PreventInstall = true
vendor.Properties.HideFromMake = true
}
- } else if m.hasVendorVariant() {
+ } else if m.hasVendorVariant() && !vendorSpecific {
// This will be available in both /system and /vendor
// or a /system directory that is available to vendor.
mod := mctx.CreateVariations(coreMode, vendorMode)
vendor := mod[1].(*Module)
vendor.Properties.UseVndk = true
squashVendorSrcs(vendor)
- } else if (mctx.SocSpecific() || mctx.DeviceSpecific()) && String(m.Properties.Sdk_version) == "" {
+ } else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
// This will be available in /vendor (or /odm) only
mod := mctx.CreateVariations(vendorMode)
vendor := mod[0].(*Module)