vendor_available:false hides a lib from vendors

When a lib is explicitly marked as `vendor_available: false`, then it
can't be directly depended by a vendor lib which is installed to /vendor
partition. This is to hide some VNDK libs (including llndk) from vendors
so that platform owners can have a freedom of modifying their ABI
without breaking vendors.

In addition, the list of the private libs are exported to the make world
as VNDK_PRIVATE_LIBRARIES.

Also, fixed a bug that allowed a vndk lib to link against to vendor
library (or vendor variant of a system lib) if the lib is prebuilt.

Bug: 64730695
Bug: 64994918
Test: Add `vendor_available: false` to libft2 and libcompiler_rt.
Add the libs to shared_libs property of a vendor library in soong
(i.e. libnbaio_mono). The build fails with the error message.

Change-Id: Iab575db96bb4f6739a592f3fa0a75124296bea0c
diff --git a/cc/androidmk.go b/cc/androidmk.go
index eb63065..2114031 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -89,7 +89,7 @@
 	}
 	c.subAndroidMk(&ret, c.installer)
 
-	if c.vndk() && Bool(c.VendorProperties.Vendor_available) {
+	if c.vndk() && c.hasVendorVariant() {
 		// .vendor suffix is added only when we will have two variants: core and vendor.
 		// The suffix is not added for vendor-only module.
 		ret.SubName += vendorSuffix
diff --git a/cc/cc.go b/cc/cc.go
index 4f10a11..0404cfb 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -168,16 +168,21 @@
 }
 
 type VendorProperties struct {
-	// whether this module should be allowed to install onto /vendor as
-	// well as /system. The two variants will be built separately, one
-	// like normal, and the other limited to the set of libraries and
-	// headers that are exposed to /vendor modules.
+	// whether this module should be allowed to be directly depended by other
+	// modules with `vendor: true`, `proprietary: true`, or `vendor_available:true`.
+	// If set to true, two variants will be built separately, one like
+	// normal, and the other limited to the set of libraries and headers
+	// that are exposed to /vendor modules.
 	//
 	// The vendor variant may be used with a different (newer) /system,
 	// so it shouldn't have any unversioned runtime dependencies, or
 	// make assumptions about the system that may not be true in the
 	// future.
 	//
+	// If set to false, this module becomes inaccessible from /vendor modules.
+	//
+	// Default value is true when vndk: {enabled: true} or vendor: true.
+	//
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	Vendor_available *bool
 }
@@ -388,6 +393,12 @@
 	return false
 }
 
+// Returns true only when this module is configured to have core and vendor
+// variants.
+func (c *Module) hasVendorVariant() bool {
+	return c.isVndk() || Bool(c.VendorProperties.Vendor_available)
+}
+
 type baseModuleContext struct {
 	android.BaseContext
 	moduleContextImpl
@@ -1159,7 +1170,7 @@
 
 		// Export the shared libs to the make world. In doing so, .vendor suffix
 		// is added if the lib has both core and vendor variants and this module
-		// is building against vndk. This is because the vendor variant will be
+		// is building against vndk. This is because the vendor variant will
 		// have .vendor suffix in its name in the make world. However, if the
 		// lib is a vendor-only lib or this lib is not building against vndk,
 		// then the suffix is not added.
@@ -1168,7 +1179,7 @@
 			libName := strings.TrimSuffix(name, llndkLibrarySuffix)
 			libName = strings.TrimPrefix(libName, "prebuilt_")
 			isLLndk := inList(libName, llndkLibraries)
-			if c.vndk() && (Bool(cc.VendorProperties.Vendor_available) || isLLndk) {
+			if c.vndk() && (cc.hasVendorVariant() || isLLndk) {
 				libName += vendorSuffix
 			}
 			// Note: the order of libs in this list is not important because
@@ -1311,15 +1322,15 @@
 	}
 
 	// Sanity check
-	if Bool(m.VendorProperties.Vendor_available) && mctx.Vendor() {
+	if m.VendorProperties.Vendor_available != nil && mctx.Vendor() {
 		mctx.PropertyErrorf("vendor_available",
 			"doesn't make sense at the same time as `vendor: true` or `proprietary: true`")
 		return
 	}
 	if vndk := m.vndkdep; vndk != nil {
-		if vndk.isVndk() && !Bool(m.VendorProperties.Vendor_available) {
+		if vndk.isVndk() && m.VendorProperties.Vendor_available == nil {
 			mctx.PropertyErrorf("vndk",
-				"has to define `vendor_available: true` to enable vndk")
+				"vendor_available must be set to either true or false when `vndk: {enabled: true}`")
 			return
 		}
 		if !vndk.isVndk() && vndk.isVndkSp() {
@@ -1337,7 +1348,7 @@
 		// LL-NDK stubs only exist in the vendor variant, since the
 		// real libraries will be used in the core variant.
 		mctx.CreateVariations(vendorMode)
-	} else if Bool(m.VendorProperties.Vendor_available) {
+	} else if m.hasVendorVariant() {
 		// This will be available in both /system and /vendor
 		// or a /system directory that is available to vendor.
 		mod := mctx.CreateVariations(coreMode, vendorMode)
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index c3d3462..30c4d4c 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -50,6 +50,11 @@
 
 	// Whether the system library uses symbol versions.
 	Unversioned bool
+
+	// whether this module can be directly depended upon by libs that are installed to /vendor.
+	// When set to false, this module can only be depended on by VNDK libraries, not vendor
+	// libraries. This effectively hides this module from vendors. Default value is true.
+	Vendor_available bool
 }
 
 type llndkStubDecorator struct {
@@ -149,6 +154,7 @@
 	stub := &llndkStubDecorator{
 		libraryDecorator: library,
 	}
+	stub.Properties.Vendor_available = true
 	module.compiler = stub
 	module.linker = stub
 	module.installer = nil
diff --git a/cc/makevars.go b/cc/makevars.go
index 2c6af70..295b4ac 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -62,6 +62,7 @@
 	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(vndkCoreLibraries, " "))
 	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(vndkSpLibraries, " "))
 	ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
+	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
 
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
diff --git a/cc/vndk.go b/cc/vndk.go
index 395069b..860678d 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -27,8 +27,8 @@
 		// declared as a VNDK or VNDK-SP module. The vendor variant
 		// will be installed in /system instead of /vendor partition.
 		//
-		// `vendor_available: true` must set to together for VNDK
-		// modules.
+		// `vendor_vailable` must be explicitly set to either true or
+		// false together with `vndk: {enabled: true}`.
 		Enabled *bool
 
 		// declared as a VNDK-SP module, which is a subset of VNDK.
@@ -81,6 +81,24 @@
 	if to.linker == nil {
 		return
 	}
+	if !vndk.isVndk() {
+		// Non-VNDK modules (those installed to /vendor) can't depend on modules marked with
+		// vendor_available: false.
+		violation := false
+		if lib, ok := to.linker.(*llndkStubDecorator); ok && !lib.Properties.Vendor_available {
+			violation = true
+		} else {
+			if _, ok := to.linker.(libraryInterface); ok && to.VendorProperties.Vendor_available != nil && !Bool(to.VendorProperties.Vendor_available) {
+				// Vendor_available == nil && !Bool(Vendor_available) should be okay since
+				// it means a vendor-only library which is a valid dependency for non-VNDK
+				// modules.
+				violation = true
+			}
+		}
+		if violation {
+			ctx.ModuleErrorf("Vendor module that is not VNDK should not link to %q which is marked as `vendor_available: false`", to.Name())
+		}
+	}
 	if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
 		// Check only shared libraries.
 		// Other (static and LL-NDK) libraries are allowed to link.
@@ -102,16 +120,17 @@
 }
 
 var (
-	vndkCoreLibraries []string
-	vndkSpLibraries   []string
-	llndkLibraries    []string
-	vndkLibrariesLock sync.Mutex
+	vndkCoreLibraries    []string
+	vndkSpLibraries      []string
+	llndkLibraries       []string
+	vndkPrivateLibraries []string
+	vndkLibrariesLock    sync.Mutex
 )
 
 // gather list of vndk-core, vndk-sp, and ll-ndk libs
 func vndkMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok {
-		if _, ok := m.linker.(*llndkStubDecorator); ok {
+		if lib, ok := m.linker.(*llndkStubDecorator); ok {
 			vndkLibrariesLock.Lock()
 			defer vndkLibrariesLock.Unlock()
 			name := strings.TrimSuffix(m.Name(), llndkLibrarySuffix)
@@ -119,22 +138,40 @@
 				llndkLibraries = append(llndkLibraries, name)
 				sort.Strings(llndkLibraries)
 			}
-		} else if lib, ok := m.linker.(*libraryDecorator); ok && lib.shared() {
-			if m.vndkdep.isVndk() {
-				vndkLibrariesLock.Lock()
-				defer vndkLibrariesLock.Unlock()
-				if m.vndkdep.isVndkSp() {
-					if !inList(m.Name(), vndkSpLibraries) {
-						vndkSpLibraries = append(vndkSpLibraries, m.Name())
-						sort.Strings(vndkSpLibraries)
+			if !lib.Properties.Vendor_available {
+				if !inList(name, vndkPrivateLibraries) {
+					vndkPrivateLibraries = append(vndkPrivateLibraries, name)
+					sort.Strings(vndkPrivateLibraries)
+				}
+			}
+		} else {
+			lib, is_lib := m.linker.(*libraryDecorator)
+			prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
+			if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
+				name := strings.TrimPrefix(m.Name(), "prebuilt_")
+				if m.vndkdep.isVndk() {
+					vndkLibrariesLock.Lock()
+					defer vndkLibrariesLock.Unlock()
+					if m.vndkdep.isVndkSp() {
+						if !inList(name, vndkSpLibraries) {
+							vndkSpLibraries = append(vndkSpLibraries, name)
+							sort.Strings(vndkSpLibraries)
+						}
+					} else {
+						if !inList(name, vndkCoreLibraries) {
+							vndkCoreLibraries = append(vndkCoreLibraries, name)
+							sort.Strings(vndkCoreLibraries)
+						}
 					}
-				} else {
-					if !inList(m.Name(), vndkCoreLibraries) {
-						vndkCoreLibraries = append(vndkCoreLibraries, m.Name())
-						sort.Strings(vndkCoreLibraries)
+					if !Bool(m.VendorProperties.Vendor_available) {
+						if !inList(name, vndkPrivateLibraries) {
+							vndkPrivateLibraries = append(vndkPrivateLibraries, name)
+							sort.Strings(vndkPrivateLibraries)
+						}
 					}
 				}
 			}
 		}
+
 	}
 }