Add a normal test app, i.e. one installed in /data.
As opposed to the other apps, it's installed the normal way after the
system server has been restarted.
At the same time switch to using data dependencies instead of java
resources for the test apps.
Test: atest libnativeloader_e2e_tests
Bug: 137356719
Bug: 237577392
Change-Id: Ia89748f87a53418a8ec324a7934064ca34821e8f
diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp
index 1eee883..db367bc 100644
--- a/libnativeloader/test/Android.bp
+++ b/libnativeloader/test/Android.bp
@@ -30,8 +30,7 @@
}
// This app is just an intermediate container to be able to include the .so
-// library as a java resource in the host test. It's not actually installed or
-// started.
+// library in the host test. It's not actually installed or started.
android_test_helper_app {
name: "library_container_app",
defaults: ["art_module_source_build_java_defaults"],
@@ -96,18 +95,30 @@
srcs: ["src/android/test/app/VendorAppTest.java"],
}
+// A normal app installed in /data.
+android_test_helper_app {
+ name: "loadlibrarytest_data_app",
+ defaults: ["loadlibrarytest_app_defaults"],
+ manifest: "loadlibrarytest_data_app_manifest.xml",
+ srcs: ["src/android/test/app/DataAppTest.java"],
+}
+
java_test_host {
name: "libnativeloader_e2e_tests",
defaults: ["art_module_source_build_java_defaults"],
srcs: ["src/android/test/hostside/*.java"],
- libs: ["tradefed"],
- java_resources: [
+ libs: [
+ "compatibility-tradefed",
+ "tradefed",
+ ],
+ data: [
":library_container_app",
":loadlibrarytest_system_priv_app",
":loadlibrarytest_system_app",
":loadlibrarytest_system_ext_app",
":loadlibrarytest_product_app",
":loadlibrarytest_vendor_app",
+ ":loadlibrarytest_data_app",
],
test_config: "libnativeloader_e2e_tests.xml",
test_suites: ["general-tests"],
diff --git a/libnativeloader/test/loadlibrarytest_data_app_manifest.xml b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml
new file mode 100644
index 0000000..bd151e3
--- /dev/null
+++ b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.test.app.data">
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.test.app.data" />
+ <application>
+ <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" />
+ <!--libbar.oem2.so is left out -->
+ <uses-native-library android:required="false" android:name="libfoo.product1.so" />
+ <uses-native-library android:required="false" android:name="libbar.product1.so" />
+ </application>
+</manifest>
+
diff --git a/libnativeloader/test/src/android/test/app/DataAppTest.java b/libnativeloader/test/src/android/test/app/DataAppTest.java
new file mode 100644
index 0000000..7973b8b
--- /dev/null
+++ b/libnativeloader/test/src/android/test/app/DataAppTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.app;
+
+import android.test.lib.TestUtils;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DataAppTest {
+ @Test
+ public void testLoadLibraries() {
+ System.loadLibrary("foo.oem1");
+ System.loadLibrary("bar.oem1");
+ System.loadLibrary("foo.oem2");
+ TestUtils.assertLinkerNamespaceError("bar.oem2"); // Missing <uses-native-library>.
+ System.loadLibrary("foo.product1");
+ System.loadLibrary("bar.product1");
+ }
+}
diff --git a/libnativeloader/test/src/android/test/app/SystemAppTest.java b/libnativeloader/test/src/android/test/app/SystemAppTest.java
index faf891f..dd29cad 100644
--- a/libnativeloader/test/src/android/test/app/SystemAppTest.java
+++ b/libnativeloader/test/src/android/test/app/SystemAppTest.java
@@ -21,7 +21,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-// These tests are run in both /system and /system_ext.
+// These tests are run from /system/app, /system/priv-app, and /system_ext/app.
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SystemAppTest {
diff --git a/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
index 06cdea3..18ed417 100644
--- a/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
+++ b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
@@ -19,6 +19,8 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.invoker.IInvocationContext;
@@ -54,19 +56,23 @@
@BeforeClassWithInfo
public static void beforeClassWithDevice(TestInformation testInfo) throws Exception {
- DeviceContext ctx = new DeviceContext(testInfo.getContext(), testInfo.getDevice());
+ DeviceContext ctx = new DeviceContext(
+ testInfo.getContext(), testInfo.getDevice(), testInfo.getBuildInfo());
// A soft reboot is slow, so do setup for all tests and reboot once.
ctx.mDevice.remountSystemWritable();
- try (ZipFile libApk = openLibContainerApk()) {
+
+ File libContainerApk = ctx.mBuildHelper.getTestFile("library_container_app.apk");
+ try (ZipFile libApk = new ZipFile(libContainerApk)) {
ctx.pushSystemOemLibs(libApk);
ctx.pushProductLibs(libApk);
}
- // "Install" apps in various partitions through plain adb push. We need them in these
- // locations to test library loading restrictions, so we cannot use
- // ITestDevice.installPackage for it since it only installs in /data.
+ // "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
+ // loadlibrarytest_data_app we cannot use ITestDevice.installPackage for it since it only
+ // installs in /data.
// For testSystemPrivApp
ctx.pushApk("loadlibrarytest_system_priv_app", "/system/priv-app");
@@ -85,13 +91,21 @@
ctx.softReboot();
+ // For testDataApp. Install this the normal way after the system server restart.
+ ctx.installPackage("loadlibrarytest_data_app");
+
testInfo.properties().put(CLEANUP_PATHS_KEY, ctx.mCleanup.getPathList());
}
@AfterClassWithInfo
public static void afterClassWithDevice(TestInformation testInfo) throws Exception {
+ ITestDevice device = testInfo.getDevice();
+
+ // Uninstall loadlibrarytest_data_app.
+ device.uninstallPackage("android.test.app.data");
+
String cleanupPathList = testInfo.properties().get(CLEANUP_PATHS_KEY);
- CleanupPaths cleanup = new CleanupPaths(testInfo.getDevice(), cleanupPathList);
+ CleanupPaths cleanup = new CleanupPaths(device, cleanupPathList);
cleanup.cleanup();
}
@@ -123,6 +137,11 @@
runDeviceTests("android.test.app.vendor", "android.test.app.VendorAppTest");
}
+ @Test
+ public void testDataApp() throws Exception {
+ runDeviceTests("android.test.app.data", "android.test.app.DataAppTest");
+ }
+
// Utility class that keeps track of a set of paths the need to be deleted after testing.
private static class CleanupPaths {
private ITestDevice mDevice;
@@ -171,12 +190,14 @@
private static class DeviceContext implements AutoCloseable {
IInvocationContext mContext;
ITestDevice mDevice;
+ CompatibilityBuildHelper mBuildHelper;
CleanupPaths mCleanup;
private String mTestArch;
- DeviceContext(IInvocationContext context, ITestDevice device) {
+ DeviceContext(IInvocationContext context, ITestDevice device, IBuildInfo buildInfo) {
mContext = context;
mDevice = device;
+ mBuildHelper = new CompatibilityBuildHelper(buildInfo);
mCleanup = new CleanupPaths(mDevice);
}
@@ -228,15 +249,14 @@
assertThat(mDevice.pushString(fileContents, destPath)).isTrue();
}
- // Like pushString, but extracts a Java resource and pushes that.
- void pushResource(String resourceName, String destPath) throws Exception {
- File hostTempFile = extractResourceToTempFile(resourceName);
+ // Like pushString, but pushes a data file included in the host test.
+ void pushFile(String fileName, String destPath) throws Exception {
mCleanup.addPath(destPath);
- assertThat(mDevice.pushFile(hostTempFile, destPath)).isTrue();
+ assertThat(mDevice.pushFile(mBuildHelper.getTestFile(fileName), destPath)).isTrue();
}
void pushApk(String apkBaseName, String destPath) throws Exception {
- pushResource("/" + apkBaseName + ".apk",
+ pushFile(apkBaseName + ".apk",
destPath + "/" + apkBaseName + "/" + apkBaseName + ".apk");
}
@@ -261,6 +281,12 @@
assertThat(mDevice.pushFile(libraryTempFile, destPath)).isTrue();
}
+ void installPackage(String apkBaseName) throws Exception {
+ assertThat(mDevice.installPackage(mBuildHelper.getTestFile(apkBaseName + ".apk"),
+ false /* reinstall */))
+ .isNull();
+ }
+
String assertCommandSucceeds(String command) throws DeviceNotAvailableException {
CommandResult result = mDevice.executeShellV2Command(command);
assertWithMessage(result.toString()).that(result.getExitCode()).isEqualTo(0);
@@ -269,20 +295,6 @@
}
}
- static private ZipFile openLibContainerApk() throws Exception {
- return new ZipFile(extractResourceToTempFile("/library_container_app.apk"));
- }
-
- static private File extractResourceToTempFile(String resourceName) throws Exception {
- assertThat(resourceName).startsWith("/");
- try (InputStream inStream = LibnativeloaderTest.class.getResourceAsStream(resourceName)) {
- assertWithMessage("Failed to extract resource " + resourceName)
- .that(inStream)
- .isNotNull();
- return writeStreamToTempFile(resourceName.substring(1), inStream);
- }
- }
-
static private File writeStreamToTempFile(String tempFileBaseName, InputStream inStream)
throws Exception {
File hostTempFile = File.createTempFile(tempFileBaseName, null);