Add double_loadable property and checks for it

double_loadable is a property that tells whether a module is capable or
being loaded with other instance (possibly an older version) of the same
module in the same process. Currently, a shared library that is a member
of VNDK can be double loaded in a vendor process if the library is also
a dependency of an LLNDK library. Such libraries now must be explicitly
marked as `double_loadable: true` by the owner, or the dependency from
the LLNDK lib should be cut if the lib is not designed to be double
loaded.

Bug: 77155589
Test: m -j
Merged-In: I3b839f860cbdc01f43b59872cd7bb84ac4a7d73e
Change-Id: I3b839f860cbdc01f43b59872cd7bb84ac4a7d73e
(cherry picked from commit 89943d8be2734ab9e63ee14afe29ba67d716ab18)
diff --git a/cc/cc.go b/cc/cc.go
index 1905990..9722cf0 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -193,6 +193,15 @@
 	//
 	// Nothing happens if BOARD_VNDK_VERSION isn't set in the BoardConfig.mk
 	Vendor_available *bool
+
+	// whether this module is capable of being loaded with other instance
+	// (possibly an older version) of the same module in the same process.
+	// Currently, a shared library that is a member of VNDK (vndk: {enabled: true})
+	// can be double loaded in a vendor process if the library is also a
+	// (direct and indirect) dependency of an LLNDK library. Such libraries must be
+	// explicitly marked as `double_loadable: true` by the owner, or the dependency
+	// from the LLNDK lib should be cut if the lib is not designed to be double loaded.
+	Double_loadable *bool
 }
 
 type UnusedProperties struct {
@@ -1127,6 +1136,34 @@
 	}
 }
 
+// Tests whether the dependent library is okay to be double loaded inside a single process.
+// If a library is a member of VNDK and at the same time dependencies of an LLNDK library,
+// it is subject to be double loaded. Such lib should be explicitly marked as double_loaded: true
+// or as vndk-sp (vndk: { enabled: true, support_system_process: true}).
+func checkDoubleLoadableLibries(ctx android.ModuleContext, from *Module, to *Module) {
+	if _, ok := from.linker.(*libraryDecorator); !ok {
+		return
+	}
+
+	if inList(ctx.ModuleName(), llndkLibraries) ||
+		(from.useVndk() && Bool(from.VendorProperties.Double_loadable)) {
+		_, depIsLlndk := to.linker.(*llndkStubDecorator)
+		depIsVndkSp := false
+		if to.vndkdep != nil && to.vndkdep.isVndkSp() {
+			depIsVndkSp = true
+		}
+		depIsVndk := false
+		if to.vndkdep != nil && to.vndkdep.isVndk() {
+			depIsVndk = true
+		}
+		depIsDoubleLoadable := Bool(to.VendorProperties.Double_loadable)
+		if !depIsLlndk && !depIsVndkSp && !depIsDoubleLoadable && depIsVndk {
+			ctx.ModuleErrorf("links VNDK library %q that isn't double_loadable.",
+				ctx.OtherModuleName(to))
+		}
+	}
+}
+
 // Convert dependencies to paths.  Returns a PathDeps containing paths
 func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
@@ -1225,6 +1262,7 @@
 			}
 
 			checkLinkType(ctx, c, ccDep, t)
+			checkDoubleLoadableLibries(ctx, c, ccDep)
 		}
 
 		var ptr *android.Paths