Add tests that try to load non-shared native libs in each partition.

One test case in each app that tries to load them directly, and another
one that goes through a shared library in the system partition.

Also set the appropriate Soong properties on the test apps, for what it
may be worth (doesn't seem to have any effect that we don't get by just
pushing them to the various partitions).

Test: atest libnativeloader_e2e_tests
Bug: 137356719
Bug: 237577392
Change-Id: I9e2c8162e0f0928020355a507b90f0fa76bf6b6b
diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp
index db367bc..b43a02c 100644
--- a/libnativeloader/test/Android.bp
+++ b/libnativeloader/test/Android.bp
@@ -48,6 +48,13 @@
     srcs: ["src/android/test/lib/TestUtils.java"],
 }
 
+// Test fixture that represents a shared library in /system/framework.
+java_library {
+    name: "libnativeloader_system_shared_lib",
+    installable: true,
+    srcs: ["src/android/test/systemsharedlib/SystemSharedLib.java"],
+}
+
 java_defaults {
     name: "loadlibrarytest_app_defaults",
     defaults: ["art_module_source_build_java_defaults"],
@@ -56,6 +63,7 @@
         "androidx.test.rules",
         "loadlibrarytest_test_utils",
     ],
+    libs: ["libnativeloader_system_shared_lib"],
 }
 
 android_test_helper_app {
@@ -76,6 +84,7 @@
 android_test_helper_app {
     name: "loadlibrarytest_system_ext_app",
     defaults: ["loadlibrarytest_app_defaults"],
+    system_ext_specific: true,
     manifest: "loadlibrarytest_system_ext_app_manifest.xml",
     // /system_ext should behave the same as /system, so use the same test class there.
     srcs: ["src/android/test/app/SystemAppTest.java"],
@@ -84,6 +93,7 @@
 android_test_helper_app {
     name: "loadlibrarytest_product_app",
     defaults: ["loadlibrarytest_app_defaults"],
+    product_specific: true,
     manifest: "loadlibrarytest_product_app_manifest.xml",
     srcs: ["src/android/test/app/ProductAppTest.java"],
 }
@@ -91,6 +101,7 @@
 android_test_helper_app {
     name: "loadlibrarytest_vendor_app",
     defaults: ["loadlibrarytest_app_defaults"],
+    vendor: true,
     manifest: "loadlibrarytest_vendor_app_manifest.xml",
     srcs: ["src/android/test/app/VendorAppTest.java"],
 }
@@ -113,6 +124,7 @@
     ],
     data: [
         ":library_container_app",
+        ":libnativeloader_system_shared_lib",
         ":loadlibrarytest_system_priv_app",
         ":loadlibrarytest_system_app",
         ":loadlibrarytest_system_ext_app",
diff --git a/libnativeloader/test/loadlibrarytest_data_app_manifest.xml b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml
index bd151e3..9b663e6 100644
--- a/libnativeloader/test/loadlibrarytest_data_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml
@@ -20,6 +20,7 @@
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.test.app.data" />
     <application>
+        <uses-library android:name="android.test.systemsharedlib" />
         <uses-native-library android:required="false" android:name="libfoo.oem1.so" />
         <uses-native-library android:required="false" android:name="libbar.oem1.so" />
         <uses-native-library android:required="false" android:name="libfoo.oem2.so" />
diff --git a/libnativeloader/test/loadlibrarytest_product_app_manifest.xml b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml
index 2ff0552..c1d997a 100644
--- a/libnativeloader/test/loadlibrarytest_product_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml
@@ -20,6 +20,7 @@
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.test.app.product" />
     <application>
+        <uses-library android:name="android.test.systemsharedlib" />
         <uses-native-library android:required="false" android:name="libfoo.oem1.so" />
         <uses-native-library android:required="false" android:name="libbar.oem1.so" />
         <uses-native-library android:required="false" android:name="libfoo.oem2.so" />
diff --git a/libnativeloader/test/loadlibrarytest_system_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml
index ee18030..5c6af09 100644
--- a/libnativeloader/test/loadlibrarytest_system_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml
@@ -20,6 +20,7 @@
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.test.app.system" />
     <application>
+        <uses-library android:name="android.test.systemsharedlib" />
         <!-- System apps get a shared classloader namespace, so they don't need
              uses-native-library entries for anything in /system. -->
         <uses-native-library android:required="false" android:name="libfoo.product1.so" />
diff --git a/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml
index dc45259..961f9ba 100644
--- a/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml
@@ -20,6 +20,7 @@
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.test.app.system_ext" />
     <application>
+        <uses-library android:name="android.test.systemsharedlib" />
         <!-- System apps get a shared classloader namespace, so they don't need
              uses-native-library entries for anything in /system. -->
         <uses-native-library android:required="false" android:name="libfoo.product1.so" />
diff --git a/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml
index efba587..f4bf3c0 100644
--- a/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml
@@ -20,6 +20,7 @@
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.test.app.system_priv" />
     <application>
+        <uses-library android:name="android.test.systemsharedlib" />
         <!-- System apps get a shared classloader namespace, so they don't need
              uses-native-library entries for anything in /system. -->
         <uses-native-library android:required="false" android:name="libfoo.product1.so" />
diff --git a/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml
index 8a98e3c..1a8cbcc 100644
--- a/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml
@@ -20,6 +20,7 @@
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="android.test.app.vendor" />
     <application>
+        <uses-library android:name="android.test.systemsharedlib" />
         <uses-native-library android:required="false" android:name="libfoo.oem1.so" />
         <uses-native-library android:required="false" android:name="libbar.oem1.so" />
         <uses-native-library android:required="false" android:name="libfoo.oem2.so" />
diff --git a/libnativeloader/test/src/android/test/app/DataAppTest.java b/libnativeloader/test/src/android/test/app/DataAppTest.java
index 7973b8b..db97e8d 100644
--- a/libnativeloader/test/src/android/test/app/DataAppTest.java
+++ b/libnativeloader/test/src/android/test/app/DataAppTest.java
@@ -17,6 +17,7 @@
 package android.test.app;
 
 import android.test.lib.TestUtils;
+import android.test.systemsharedlib.SystemSharedLib;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 import org.junit.Test;
@@ -26,12 +27,29 @@
 @RunWith(AndroidJUnit4.class)
 public class DataAppTest {
     @Test
-    public void testLoadLibraries() {
+    public void testLoadExtendedPublicLibraries() {
         System.loadLibrary("foo.oem1");
         System.loadLibrary("bar.oem1");
         System.loadLibrary("foo.oem2");
-        TestUtils.assertLinkerNamespaceError("bar.oem2"); // Missing <uses-native-library>.
+        TestUtils.assertLinkerNamespaceError(
+                () -> System.loadLibrary("bar.oem2")); // Missing <uses-native-library>.
         System.loadLibrary("foo.product1");
         System.loadLibrary("bar.product1");
     }
+
+    @Test
+    public void testLoadPrivateLibraries() {
+        TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1"));
+        TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1"));
+        TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1"));
+    }
+
+    @Test
+    public void testLoadPrivateLibrariesViaSystemSharedLib() {
+        // TODO(b/237577392): Fix this use case.
+        TestUtils.assertLinkerNamespaceError(() -> SystemSharedLib.loadLibrary("system_private2"));
+
+        TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2"));
+        TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2"));
+    }
 }
diff --git a/libnativeloader/test/src/android/test/app/ProductAppTest.java b/libnativeloader/test/src/android/test/app/ProductAppTest.java
index 592c3ed..a9b8697 100644
--- a/libnativeloader/test/src/android/test/app/ProductAppTest.java
+++ b/libnativeloader/test/src/android/test/app/ProductAppTest.java
@@ -17,6 +17,7 @@
 package android.test.app;
 
 import android.test.lib.TestUtils;
+import android.test.systemsharedlib.SystemSharedLib;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 import org.junit.Test;
@@ -26,12 +27,29 @@
 @RunWith(AndroidJUnit4.class)
 public class ProductAppTest {
     @Test
-    public void testLoadLibraries() {
+    public void testLoadExtendedPublicLibraries() {
         System.loadLibrary("foo.oem1");
         System.loadLibrary("bar.oem1");
         System.loadLibrary("foo.oem2");
-        TestUtils.assertLinkerNamespaceError("bar.oem2"); // Missing <uses-native-library>.
+        TestUtils.assertLinkerNamespaceError(
+                () -> System.loadLibrary("bar.oem2")); // Missing <uses-native-library>.
         System.loadLibrary("foo.product1");
         System.loadLibrary("bar.product1");
     }
+
+    @Test
+    public void testLoadPrivateLibraries() {
+        TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1"));
+        System.loadLibrary("product_private1");
+        TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1"));
+    }
+
+    @Test
+    public void testLoadPrivateLibrariesViaSystemSharedLib() {
+        // TODO(b/237577392): Fix this use case.
+        TestUtils.assertLinkerNamespaceError(() -> SystemSharedLib.loadLibrary("system_private2"));
+
+        TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2"));
+        TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2"));
+    }
 }
diff --git a/libnativeloader/test/src/android/test/app/SystemAppTest.java b/libnativeloader/test/src/android/test/app/SystemAppTest.java
index dd29cad..6644478 100644
--- a/libnativeloader/test/src/android/test/app/SystemAppTest.java
+++ b/libnativeloader/test/src/android/test/app/SystemAppTest.java
@@ -16,6 +16,8 @@
 
 package android.test.app;
 
+import android.test.lib.TestUtils;
+import android.test.systemsharedlib.SystemSharedLib;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 import org.junit.Test;
@@ -26,7 +28,7 @@
 @RunWith(AndroidJUnit4.class)
 public class SystemAppTest {
     @Test
-    public void testLoadLibraries() {
+    public void testLoadExtendedPublicLibraries() {
         System.loadLibrary("foo.oem1");
         System.loadLibrary("bar.oem1");
         System.loadLibrary("foo.oem2");
@@ -34,4 +36,18 @@
         System.loadLibrary("foo.product1");
         System.loadLibrary("bar.product1");
     }
+
+    @Test
+    public void testLoadPrivateLibraries() {
+        System.loadLibrary("system_private1");
+        TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1"));
+        TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1"));
+    }
+
+    @Test
+    public void testLoadPrivateLibrariesViaSystemSharedLib() {
+        SystemSharedLib.loadLibrary("system_private2");
+        TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2"));
+        TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2"));
+    }
 }
diff --git a/libnativeloader/test/src/android/test/app/VendorAppTest.java b/libnativeloader/test/src/android/test/app/VendorAppTest.java
index bd6d637..5187ac8 100644
--- a/libnativeloader/test/src/android/test/app/VendorAppTest.java
+++ b/libnativeloader/test/src/android/test/app/VendorAppTest.java
@@ -17,6 +17,7 @@
 package android.test.app;
 
 import android.test.lib.TestUtils;
+import android.test.systemsharedlib.SystemSharedLib;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 import org.junit.Test;
@@ -26,12 +27,32 @@
 @RunWith(AndroidJUnit4.class)
 public class VendorAppTest {
     @Test
-    public void testLoadLibraries() {
-        TestUtils.assertLinkerNamespaceError("foo.oem1");
-        TestUtils.assertLinkerNamespaceError("bar.oem1");
-        TestUtils.assertLinkerNamespaceError("foo.oem2");
-        TestUtils.assertLinkerNamespaceError("bar.oem2");
+    public void testLoadExtendedPublicLibraries() {
+        TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("foo.oem1"));
+        TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("bar.oem1"));
+        TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("foo.oem2"));
+        TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("bar.oem2"));
         System.loadLibrary("foo.product1");
         System.loadLibrary("bar.product1");
     }
+
+    @Test
+    public void testLoadPrivateLibraries() {
+        TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1"));
+        TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1"));
+        // TODO(mast): The vendor app fails to load a private vendor library because it gets
+        // classified as untrusted_app in SELinux, which doesn't have access to vendor_file. Even an
+        // app in /vendor/priv-app, which gets classified as priv_app, still doesn't have access to
+        // vendor_file. Check that the test setup is correct and if this is WAI.
+        TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1"));
+    }
+
+    @Test
+    public void testLoadPrivateLibrariesViaSystemSharedLib() {
+        // TODO(b/237577392): Fix this use case.
+        TestUtils.assertLinkerNamespaceError(() -> SystemSharedLib.loadLibrary("system_private2"));
+
+        TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2"));
+        TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2"));
+    }
 }
diff --git a/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
index 18ed417..670e63c 100644
--- a/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
+++ b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
@@ -65,9 +65,11 @@
 
         File libContainerApk = ctx.mBuildHelper.getTestFile("library_container_app.apk");
         try (ZipFile libApk = new ZipFile(libContainerApk)) {
-            ctx.pushSystemOemLibs(libApk);
-            ctx.pushProductLibs(libApk);
+            ctx.pushExtendedPublicSystemOemLibs(libApk);
+            ctx.pushExtendedPublicProductLibs(libApk);
+            ctx.pushPrivateLibs(libApk);
         }
+        ctx.pushSystemSharedLib();
 
         // "Install" apps in various partitions through plain adb push followed by a soft reboot. We
         // need them in these locations to test library loading restrictions, so for all except
@@ -203,7 +205,7 @@
 
         public void close() throws DeviceNotAvailableException { mCleanup.cleanup(); }
 
-        void pushSystemOemLibs(ZipFile libApk) throws Exception {
+        void pushExtendedPublicSystemOemLibs(ZipFile libApk) throws Exception {
             pushNativeTestLib(libApk, "/system/${LIB}/libfoo.oem1.so");
             pushNativeTestLib(libApk, "/system/${LIB}/libbar.oem1.so");
             pushString("libfoo.oem1.so\n"
@@ -217,7 +219,7 @@
                     "/system/etc/public.libraries-oem2.txt");
         }
 
-        void pushProductLibs(ZipFile libApk) throws Exception {
+        void pushExtendedPublicProductLibs(ZipFile libApk) throws Exception {
             pushNativeTestLib(libApk, "/product/${LIB}/libfoo.product1.so");
             pushNativeTestLib(libApk, "/product/${LIB}/libbar.product1.so");
             pushString("libfoo.product1.so\n"
@@ -225,6 +227,26 @@
                     "/product/etc/public.libraries-product1.txt");
         }
 
+        void pushPrivateLibs(ZipFile libApk) throws Exception {
+            // Push the libraries once for each test. Since we cannot unload them, we need a fresh
+            // never-before-loaded library in each loadLibrary call.
+            for (int i = 1; i <= 2; ++i) {
+                pushNativeTestLib(libApk, "/system/${LIB}/libsystem_private" + i + ".so");
+                pushNativeTestLib(libApk, "/product/${LIB}/libproduct_private" + i + ".so");
+                pushNativeTestLib(libApk, "/vendor/${LIB}/libvendor_private" + i + ".so");
+            }
+        }
+
+        void pushSystemSharedLib() throws Exception {
+            String packageName = "android.test.systemsharedlib";
+            String path = "/system/framework/" + packageName + ".jar";
+            pushFile("libnativeloader_system_shared_lib.jar", path);
+            pushString("<permissions>\n"
+                            + "<library name=\"" + packageName + "\" file=\"" + path + "\" />\n"
+                            + "</permissions>\n",
+                    "system/etc/permissions/" + packageName + ".xml");
+        }
+
         void softReboot() throws DeviceNotAvailableException {
             assertCommandSucceeds("setprop dev.bootcomplete 0");
             assertCommandSucceeds("stop");
diff --git a/libnativeloader/test/src/android/test/lib/TestUtils.java b/libnativeloader/test/src/android/test/lib/TestUtils.java
index 1518cd0..eda9993 100644
--- a/libnativeloader/test/src/android/test/lib/TestUtils.java
+++ b/libnativeloader/test/src/android/test/lib/TestUtils.java
@@ -19,10 +19,16 @@
 import static com.google.common.truth.Truth.assertThat;
 import static org.junit.Assert.assertThrows;
 
+import org.junit.function.ThrowingRunnable;
+
 public final class TestUtils {
-    public static void assertLinkerNamespaceError(String libraryName) {
-        Throwable t =
-                assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(libraryName));
+    public static void assertLibraryNotFound(ThrowingRunnable loadLibrary) {
+        Throwable t = assertThrows(UnsatisfiedLinkError.class, loadLibrary);
+        assertThat(t.getMessage()).containsMatch("dlopen failed: library .* not found");
+    }
+
+    public static void assertLinkerNamespaceError(ThrowingRunnable loadLibrary) {
+        Throwable t = assertThrows(UnsatisfiedLinkError.class, loadLibrary);
         assertThat(t.getMessage())
                 .containsMatch("dlopen failed: .* is not accessible for the namespace");
     }
diff --git a/libnativeloader/test/src/android/test/systemsharedlib/SystemSharedLib.java b/libnativeloader/test/src/android/test/systemsharedlib/SystemSharedLib.java
new file mode 100644
index 0000000..8e2af9f
--- /dev/null
+++ b/libnativeloader/test/src/android/test/systemsharedlib/SystemSharedLib.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.systemsharedlib;
+
+public final class SystemSharedLib {
+    public static void loadLibrary(String name) { System.loadLibrary(name); }
+}