Verify that libraries in apexes don't link to implementations outside the apex

As part of removing some of the complexity in Soong around using
stub vs. implementations for shared library dependencies a syntax
will be added to Soong to allow explicitly selecting stubs vs.
implementation.  To avoid incorrect use, add a verification pass
on apexes that ensure that all transitive implementation libraries
used to link native libraries or binaries in the apex are
themselves in the apex.

Bug: 372543712
Test: TestApexVerifyNativeImplementationLibs
Flag: EXEMPT host only
Change-Id: I4aeaca00a359ce97e8f9efd2d8bffb8f9d2dc0df
diff --git a/java/app.go b/java/app.go
index fed971a..15b1114 100644
--- a/java/app.go
+++ b/java/app.go
@@ -67,6 +67,9 @@
 
 	// TestHelperApp is true if the module is a android_test_helper_app
 	TestHelperApp bool
+
+	// EmbeddedJNILibs is the list of paths to JNI libraries that were embedded in the APK.
+	EmbeddedJNILibs android.Paths
 }
 
 var AppInfoProvider = blueprint.NewProvider[*AppInfo]()
@@ -405,9 +408,18 @@
 	a.checkEmbedJnis(ctx)
 	a.generateAndroidBuildActions(ctx)
 	a.generateJavaUsedByApex(ctx)
+
+	var embeddedJniLibs []android.Path
+
+	if a.embeddedJniLibs {
+		for _, jni := range a.jniLibs {
+			embeddedJniLibs = append(embeddedJniLibs, jni.path)
+		}
+	}
 	android.SetProvider(ctx, AppInfoProvider, &AppInfo{
-		Updatable:     Bool(a.appProperties.Updatable),
-		TestHelperApp: false,
+		Updatable:       Bool(a.appProperties.Updatable),
+		TestHelperApp:   false,
+		EmbeddedJNILibs: embeddedJniLibs,
 	})
 }
 
@@ -1070,12 +1082,12 @@
 			app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
 	}
 	jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps,
-		checkNativeSdkVersion, func(dep cc.LinkableInterface) bool {
-			return !dep.IsNdk(ctx.Config()) && !dep.IsStubs()
-		})
+		checkNativeSdkVersion, func(dep cc.LinkableInterface) bool { return !dep.IsNdk(ctx.Config()) && !dep.IsStubs() })
 
 	var certificates []Certificate
 
+	var directImplementationDeps android.Paths
+	var transitiveImplementationDeps []depset.DepSet[android.Path]
 	ctx.VisitDirectDeps(func(module android.Module) {
 		otherName := ctx.OtherModuleName(module)
 		tag := ctx.OtherModuleDependencyTag(module)
@@ -1087,7 +1099,18 @@
 				ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName)
 			}
 		}
+
+		if IsJniDepTag(tag) {
+			directImplementationDeps = append(directImplementationDeps, android.OutputFileForModule(ctx, module, ""))
+			if info, ok := android.OtherModuleProvider(ctx, module, cc.ImplementationDepInfoProvider); ok {
+				transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps)
+			}
+		}
 	})
+	android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{
+		ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps),
+	})
+
 	return jniLib, prebuiltJniPackages, certificates
 }