Install transitive deps of jni libs, but not the jni libs themselves

Consider this case:

app --(jni_libs)--> libfoo --(shared_libs)--> libprivate

Only libfoo is embedded into the app. libprivate is not embedded because
libprivate is very likely to be depended on by other components in the
platform, in which case it will anyway be installed to /system/lib.
Embedding libprivate into the app will increase the storage usage as a
whole. Furthermore, if libprivate is not a shared lib but a config file
(of type prebuilt_etc), it can't be embedded and therefore must be
installed outside of the app.

However, a problem occurs when libprivate is not depended on by anyone
else. Then libprivate is not installed to the system partition, causing
an error at runtime.

This CL fixes that by making the jni_libs dependency to implement the
new SKipToTransitiveDepsTag interface. Now, jni_libs themselves are not
installed, but their transitive deps are depended on by the app
containing the jni libs.

Bug: 330276359
Test: m NfcNci and check if libnfc-nci.config is installed.
Test: m CarService and check android.hardware.automotive.evs-V2-ndk.so
is installed as well.
Test: go test ./... under soong/java

Change-Id: I04cc92b7fad768a20ec60a02b3e7534641b1e74d
diff --git a/java/app_test.go b/java/app_test.go
index 92fe224..d6ba0f1 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2043,6 +2043,44 @@
 	}
 }
 
+func TestJNITranstiveDepsInstallation(t *testing.T) {
+	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+		android_app {
+			name: "app",
+			jni_libs: ["libjni"],
+			platform_apis: true,
+		}
+
+		cc_library {
+			name: "libjni",
+			shared_libs: ["libplatform"],
+			system_shared_libs: [],
+			stl: "none",
+			required: ["librequired"],
+		}
+
+		cc_library {
+			name: "libplatform",
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "librequired",
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		`)
+
+	app := ctx.ModuleForTests("app", "android_common")
+	jniLibZip := app.Output("jnilibs.zip")
+	android.AssertPathsEndWith(t, "embedd jni lib mismatch", []string{"libjni.so"}, jniLibZip.Implicits)
+
+	install := app.Rule("Cp")
+	android.AssertPathsEndWith(t, "install dep mismatch", []string{"libplatform.so", "librequired.so"}, install.OrderOnly)
+}
+
 func TestJNISDK(t *testing.T) {
 	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
diff --git a/java/java.go b/java/java.go
index 0df96a3..fc7e5c5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -368,6 +368,17 @@
 	static bool
 }
 
+var _ android.SkipToTransitiveDepsTag = (*dependencyTag)(nil)
+
+func (depTag dependencyTag) SkipToTransitiveDeps() bool {
+	// jni_libs are not installed because they are always embedded into the app. However,
+	// transitive deps of jni_libs themselves should be installed along with the app.
+	if IsJniDepTag(depTag) {
+		return true
+	}
+	return false
+}
+
 // installDependencyTag is a dependency tag that is annotated to cause the installed files of the
 // dependency to be installed when the parent module is installed.
 type installDependencyTag struct {