diff options
Diffstat (limited to 'libnativeloader/test')
26 files changed, 1378 insertions, 203 deletions
diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp index fb9ae0d9d3..95b9b886dd 100644 --- a/libnativeloader/test/Android.bp +++ b/libnativeloader/test/Android.bp @@ -23,58 +23,179 @@ package { default_applicable_licenses: ["art_license"], } +// A native library that goes into /system or /system_ext and that depends on +// a non-public library that is linked from the system namespace. cc_library { - name: "libfoo.oem1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.oem1.so\""], - shared_libs: [ - "libbase", - ], + name: "libsystem_testlib", + min_sdk_version: "31", + stl: "libc++_static", + shared_libs: ["liblog"], + // It's difficult to add a shared_lib dependency on a non-public library + // here, so it dlopens one instead. + srcs: ["libsystem_testlib.cc"], } +// A native library that goes into /product. cc_library { - name: "libbar.oem1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.oem1.so\""], - shared_libs: [ - "libbase", - ], + name: "libproduct_testlib", + min_sdk_version: "31", + stl: "none", + srcs: [], } +// A native library that goes into /vendor. cc_library { - name: "libfoo.oem2", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.oem2.so\""], - shared_libs: [ - "libbase", + name: "libvendor_testlib", + min_sdk_version: "31", + stl: "none", + srcs: [], +} + +// This app is just an intermediate container to be able to include the .so +// 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"], + min_sdk_version: "31", + manifest: "library_container_app_manifest.xml", + compile_multilib: "both", + jni_libs: [ + "libsystem_testlib", + "libproduct_testlib", + "libvendor_testlib", ], } -cc_library { - name: "libbar.oem2", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.oem2.so\""], - shared_libs: [ - "libbase", +java_library { + name: "loadlibrarytest_test_utils", + sdk_version: "31", + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.ext.truth", ], + srcs: ["src/android/test/lib/TestUtils.java"], } -cc_library { - name: "libfoo.product1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.product1.so\""], +// Test fixture that represents a shared library in /system/framework. +java_library { + name: "libnativeloader_system_shared_lib", + sdk_version: "31", + installable: true, + srcs: ["src/android/test/systemsharedlib/SystemSharedLib.java"], +} + +// Test fixture that represents a shared library in /system_ext/framework. +java_library { + name: "libnativeloader_system_ext_shared_lib", + sdk_version: "31", + installable: true, + srcs: ["src/android/test/systemextsharedlib/SystemExtSharedLib.java"], +} + +// Test fixture that represents a shared library in /product/framework. +java_library { + name: "libnativeloader_product_shared_lib", product_specific: true, - shared_libs: [ - "libbase", + sdk_version: "31", + installable: true, + srcs: ["src/android/test/productsharedlib/ProductSharedLib.java"], +} + +// Test fixture that represents a shared library in /vendor/framework. +java_library { + name: "libnativeloader_vendor_shared_lib", + vendor: true, + sdk_version: "31", + installable: true, + srcs: ["src/android/test/vendorsharedlib/VendorSharedLib.java"], +} + +java_defaults { + name: "loadlibrarytest_app_defaults", + defaults: ["art_module_source_build_java_defaults"], + sdk_version: "31", + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.rules", + "loadlibrarytest_test_utils", + ], + libs: [ + "libnativeloader_system_shared_lib", + "libnativeloader_system_ext_shared_lib", + "libnativeloader_product_shared_lib", + "libnativeloader_vendor_shared_lib", ], } -cc_library { - name: "libbar.product1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.product1.so\""], +android_test_helper_app { + name: "loadlibrarytest_system_priv_app", + defaults: ["loadlibrarytest_app_defaults"], + manifest: "loadlibrarytest_system_priv_app_manifest.xml", + // /system/priv-app currently reuses the same test as /system/app. + srcs: ["src/android/test/app/SystemAppTest.java"], +} + +android_test_helper_app { + name: "loadlibrarytest_system_app", + defaults: ["loadlibrarytest_app_defaults"], + manifest: "loadlibrarytest_system_app_manifest.xml", + srcs: ["src/android/test/app/SystemAppTest.java"], +} + +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"], +} + +android_test_helper_app { + name: "loadlibrarytest_product_app", + defaults: ["loadlibrarytest_app_defaults"], product_specific: true, - shared_libs: [ - "libbase", + manifest: "loadlibrarytest_product_app_manifest.xml", + srcs: ["src/android/test/app/ProductAppTest.java"], +} + +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"], +} + +// 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: [ + "compatibility-tradefed", + "tradefed", + ], + data: [ + ":library_container_app", + ":libnativeloader_system_shared_lib", + ":libnativeloader_system_ext_shared_lib", + ":libnativeloader_product_shared_lib", + ":libnativeloader_vendor_shared_lib", + ":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/Android.mk b/libnativeloader/test/Android.mk deleted file mode 100644 index 95fa68af68..0000000000 --- a/libnativeloader/test/Android.mk +++ /dev/null @@ -1,72 +0,0 @@ -# -# Copyright (C) 2017 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. -# -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := public.libraries-oem1.txt -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES:= $(LOCAL_MODULE) -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) -include $(BUILD_PREBUILT) - -include $(CLEAR_VARS) -LOCAL_MODULE := public.libraries-oem2.txt -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES:= $(LOCAL_MODULE) -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) -include $(BUILD_PREBUILT) - -include $(CLEAR_VARS) -LOCAL_MODULE := public.libraries-product1.txt -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -LOCAL_SRC_FILES:= $(LOCAL_MODULE) -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC) -include $(BUILD_PREBUILT) - -include $(CLEAR_VARS) -LOCAL_PACKAGE_NAME := oemlibrarytest-system -LOCAL_MODULE_TAGS := tests -LOCAL_MANIFEST_FILE := system/AndroidManifest.xml -LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_SDK_VERSION := current -LOCAL_PROGUARD_ENABLED := disabled -LOCAL_MODULE_PATH := $(TARGET_OUT_APPS) -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -include $(BUILD_PACKAGE) - -include $(CLEAR_VARS) -LOCAL_PACKAGE_NAME := oemlibrarytest-vendor -LOCAL_MODULE_TAGS := tests -LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml -LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_SDK_VERSION := current -LOCAL_PROGUARD_ENABLED := disabled -LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_APPS) -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE -include $(BUILD_PACKAGE) diff --git a/libnativeloader/test/libnativeloader_e2e_tests.xml b/libnativeloader/test/libnativeloader_e2e_tests.xml new file mode 100644 index 0000000000..d4f6348886 --- /dev/null +++ b/libnativeloader/test/libnativeloader_e2e_tests.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2021 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. +--> +<configuration description="Config for libnativeloader e2e test cases"> + <option name="test-suite-tag" value="libnativeloader_e2e_tests" /> + <option name="test-suite-tag" value="apct" /> + <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.art.apex" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" /> + + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <!-- We push all files in LibnativeloaderTest.java, but use this + preparer to make partitions writable. That since remounting may + require a device reboot, and then it's important that the + `setenforce 0` from DisableSELinuxTargetPreparer occurs after that. --> + <option name="remount-system" value="true" /> + <option name="remount-vendor" value="true" /> + </target_preparer> + + <!-- Vendor native libraries aren't accessible by any apps by sepolicy + rules. For that they need to be labelled same_process_hal_file in a + vendor specific file_contexts file (see + https://source.android.com/docs/core/permissions/namespaces_libraries#adding-additional-native-libraries). + To avoid setting that up to test loading libvendor_private*.so, disable + sepolicy checks while running the tests. It's libnativeloader logic we + want to test here. --> + <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer"/> + + <test class="com.android.tradefed.testtype.HostTest" > + <option name="jar" value="libnativeloader_e2e_tests.jar" /> + </test> + + <!-- Only run tests if the device under test is SDK version 31 (Android 12) or above. --> + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" /> +</configuration> diff --git a/libnativeloader/test/system/AndroidManifest.xml b/libnativeloader/test/library_container_app_manifest.xml index c3048891a8..20030de7eb 100644 --- a/libnativeloader/test/system/AndroidManifest.xml +++ b/libnativeloader/test/library_container_app_manifest.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - * Copyright (C) 2018 The Android Open Source Project + * 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. @@ -16,16 +16,5 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="android.test.app.system"> - - <application> - <activity android:name="android.test.app.TestActivity" > - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> - + package="android.test.app.container"> </manifest> - diff --git a/libnativeloader/test/libsystem_testlib.cc b/libnativeloader/test/libsystem_testlib.cc new file mode 100644 index 0000000000..97d32237b4 --- /dev/null +++ b/libnativeloader/test/libsystem_testlib.cc @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#include <dlfcn.h> + +#include "log/log.h" + +static void __attribute__((constructor)) ctor() { + // Load a library that should be available to system libraries through a + // linked namespace (i.e. is not directly in /system/${LIB}), and that is not + // in public.libraries.txt. We use a real one to avoid having to set up an + // APEX test fixture and rerun linkerconfig. + void* h = dlopen("libandroidicu.so", RTLD_NOW); + if (h == nullptr) { + LOG_ALWAYS_FATAL("Failed to load dependency: %s", dlerror()); + } + dlclose(h); +} diff --git a/libnativeloader/test/loadlibrarytest_data_app_manifest.xml b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml new file mode 100644 index 0000000000..4be78f84f9 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml @@ -0,0 +1,38 @@ +<?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-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem2.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub1.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub2.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub3.oem1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_product_app_manifest.xml b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml new file mode 100644 index 0000000000..9061c396e1 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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.product"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.product" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem2.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub1.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub2.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub3.oem1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_system_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml new file mode 100644 index 0000000000..7ee7532d1c --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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.system"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.system" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <!-- System apps get a shared classloader namespace, so they don't need + uses-native-library entries for anything in /system or /system_ext. --> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml new file mode 100644 index 0000000000..a2c1a2c8db --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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.system_ext"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.system_ext" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <!-- System apps get a shared classloader namespace, so they don't need + uses-native-library entries for anything in /system or /system_ext. --> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml new file mode 100644 index 0000000000..87a30cec12 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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.system_priv"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.system_priv" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <!-- System apps get a shared classloader namespace, so they don't need + uses-native-library entries for anything in /system or /system_ext. --> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml new file mode 100644 index 0000000000..b3434fb930 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2018 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.vendor"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.vendor" /> + <application> + <uses-library android:required="false" android:name="android.test.systemsharedlib" /> + <uses-library android:required="false" android:name="android.test.systemextsharedlib" /> + <uses-library android:required="false" android:name="android.test.productsharedlib" /> + <uses-library android:required="false" android:name="android.test.vendorsharedlib" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub.oem2.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub1.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub2.oem1.so" /> + <uses-native-library android:required="false" android:name="libsystem_extpub3.oem1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub1.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub2.product1.so" /> + <uses-native-library android:required="false" android:name="libproduct_extpub3.product1.so" /> + </application> +</manifest> + diff --git a/libnativeloader/test/public.libraries-oem1.txt b/libnativeloader/test/public.libraries-oem1.txt deleted file mode 100644 index f9433e2a04..0000000000 --- a/libnativeloader/test/public.libraries-oem1.txt +++ /dev/null @@ -1,2 +0,0 @@ -libfoo.oem1.so -libbar.oem1.so diff --git a/libnativeloader/test/public.libraries-oem2.txt b/libnativeloader/test/public.libraries-oem2.txt deleted file mode 100644 index de6bdb08e0..0000000000 --- a/libnativeloader/test/public.libraries-oem2.txt +++ /dev/null @@ -1,2 +0,0 @@ -libfoo.oem2.so -libbar.oem2.so diff --git a/libnativeloader/test/public.libraries-product1.txt b/libnativeloader/test/public.libraries-product1.txt deleted file mode 100644 index 358154c626..0000000000 --- a/libnativeloader/test/public.libraries-product1.txt +++ /dev/null @@ -1,2 +0,0 @@ -libfoo.product1.so -libbar.product1.so diff --git a/libnativeloader/test/runtest.sh b/libnativeloader/test/runtest.sh deleted file mode 100755 index 40beb5b4d5..0000000000 --- a/libnativeloader/test/runtest.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -adb root -adb remount -adb sync -adb shell stop -adb shell start -sleep 5 # wait until device reboots -adb logcat -c; -adb shell am start -n android.test.app.system/android.test.app.TestActivity -adb shell am start -n android.test.app.vendor/android.test.app.TestActivity -adb logcat | grep android.test.app 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 0000000000..9403494df6 --- /dev/null +++ b/libnativeloader/test/src/android/test/app/DataAppTest.java @@ -0,0 +1,112 @@ +/* + * 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 android.test.productsharedlib.ProductSharedLib; +import android.test.systemextsharedlib.SystemExtSharedLib; +import android.test.systemsharedlib.SystemSharedLib; +import android.test.vendorsharedlib.VendorSharedLib; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class DataAppTest { + @Test + public void testLoadExtendedPublicLibraries() { + System.loadLibrary("system_extpub.oem1"); + System.loadLibrary("system_extpub.oem2"); + System.loadLibrary("system_extpub1.oem1"); + TestUtils.assertLinkerNamespaceError( // Missing <uses-native-library>. + () -> System.loadLibrary("system_extpub_nouses.oem2")); + System.loadLibrary("product_extpub.product1"); + System.loadLibrary("product_extpub1.product1"); + } + + @Test + public void testLoadPrivateLibraries() { + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1")); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1")); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1")); + } + + @Test + public void testLoadExtendedPublicLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_extpub2.oem1"); + SystemSharedLib.loadLibrary("product_extpub2.product1"); + } + + @Test + public void testLoadPrivateLibrariesViaSystemSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemSharedLib.loadLibrary("system_private2"); + // SystemSharedLib.loadLibrary("systemext_private2"); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2")); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2")); + } + + @Test + public void testLoadPrivateLibrariesViaSystemExtSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemExtSharedLib.loadLibrary("system_private3"); + // SystemExtSharedLib.loadLibrary("systemext_private3"); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3")); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3")); + } + + @Test + public void testLoadPrivateLibrariesViaProductSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> ProductSharedLib.loadLibrary("system_private4")); + TestUtils.assertLinkerNamespaceError( + () -> ProductSharedLib.loadLibrary("systemext_private4")); + ProductSharedLib.loadLibrary("product_private4"); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("vendor_private4")); + } + + @Test + public void testLoadPrivateLibrariesViaVendorSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> VendorSharedLib.loadLibrary("system_private5")); + TestUtils.assertLinkerNamespaceError( + () -> VendorSharedLib.loadLibrary("systemext_private5")); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("product_private5")); + VendorSharedLib.loadLibrary("vendor_private5"); + } + + @Test + public void testLoadExtendedPublicLibrariesWithAbsolutePaths() { + System.load(TestUtils.libPath("/system", "system_extpub3.oem1")); + System.load(TestUtils.libPath("/product", "product_extpub3.product1")); + } + + @Test + public void testLoadPrivateLibrariesWithAbsolutePaths() { + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system", "system_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system_ext", "systemext_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/product", "product_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/vendor", "vendor_private6"))); + } +} diff --git a/libnativeloader/test/src/android/test/app/ProductAppTest.java b/libnativeloader/test/src/android/test/app/ProductAppTest.java new file mode 100644 index 0000000000..7ec817b642 --- /dev/null +++ b/libnativeloader/test/src/android/test/app/ProductAppTest.java @@ -0,0 +1,111 @@ +/* + * 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 android.test.productsharedlib.ProductSharedLib; +import android.test.systemextsharedlib.SystemExtSharedLib; +import android.test.systemsharedlib.SystemSharedLib; +import android.test.vendorsharedlib.VendorSharedLib; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class ProductAppTest { + @Test + public void testLoadExtendedPublicLibraries() { + System.loadLibrary("system_extpub.oem1"); + System.loadLibrary("system_extpub.oem2"); + System.loadLibrary("system_extpub1.oem1"); + TestUtils.assertLinkerNamespaceError( // Missing <uses-native-library>. + () -> System.loadLibrary("system_extpub_nouses.oem2")); + System.loadLibrary("product_extpub.product1"); + System.loadLibrary("product_extpub1.product1"); + } + + @Test + public void testLoadPrivateLibraries() { + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1")); + System.loadLibrary("product_private1"); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1")); + } + + @Test + public void testLoadExtendedPublicLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_extpub2.oem1"); + SystemSharedLib.loadLibrary("product_extpub2.product1"); + } + + @Test + public void testLoadPrivateLibrariesViaSystemSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemSharedLib.loadLibrary("system_private2"); + // SystemSharedLib.loadLibrary("systemext_private2"); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2")); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2")); + } + + @Test + public void testLoadPrivateLibrariesViaSystemExtSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemExtSharedLib.loadLibrary("system_private3"); + // SystemExtSharedLib.loadLibrary("systemext_private3"); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3")); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3")); + } + + @Test + public void testLoadPrivateLibrariesViaProductSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> ProductSharedLib.loadLibrary("system_private4")); + TestUtils.assertLinkerNamespaceError( + () -> ProductSharedLib.loadLibrary("systemext_private4")); + ProductSharedLib.loadLibrary("product_private4"); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("vendor_private4")); + } + + @Test + public void testLoadPrivateLibrariesViaVendorSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> VendorSharedLib.loadLibrary("system_private5")); + TestUtils.assertLinkerNamespaceError( + () -> VendorSharedLib.loadLibrary("systemext_private5")); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("product_private5")); + VendorSharedLib.loadLibrary("vendor_private5"); + } + + @Test + public void testLoadExtendedPublicLibrariesWithAbsolutePaths() { + System.load(TestUtils.libPath("/system", "system_extpub3.oem1")); + System.load(TestUtils.libPath("/product", "product_extpub3.product1")); + } + + @Test + public void testLoadPrivateLibrariesWithAbsolutePaths() { + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system", "system_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system_ext", "systemext_private6"))); + System.load(TestUtils.libPath("/product", "product_private6")); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/vendor", "vendor_private6"))); + } +} diff --git a/libnativeloader/test/src/android/test/app/SystemAppTest.java b/libnativeloader/test/src/android/test/app/SystemAppTest.java new file mode 100644 index 0000000000..cabdfb7e75 --- /dev/null +++ b/libnativeloader/test/src/android/test/app/SystemAppTest.java @@ -0,0 +1,106 @@ +/* + * 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 android.test.productsharedlib.ProductSharedLib; +import android.test.systemextsharedlib.SystemExtSharedLib; +import android.test.systemsharedlib.SystemSharedLib; +import android.test.vendorsharedlib.VendorSharedLib; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +// These tests are run from /system/app, /system/priv-app, and /system_ext/app. +@MediumTest +@RunWith(AndroidJUnit4.class) +public class SystemAppTest { + @Test + public void testLoadExtendedPublicLibraries() { + System.loadLibrary("system_extpub.oem1"); + System.loadLibrary("system_extpub.oem2"); + System.loadLibrary("system_extpub1.oem1"); + // Missing <uses-native-library> not relevant for system apps, which have shared classloader + // namespaces. + System.loadLibrary("system_extpub_nouses.oem2"); + System.loadLibrary("product_extpub.product1"); + System.loadLibrary("product_extpub1.product1"); + } + + @Test + public void testLoadPrivateLibraries() { + System.loadLibrary("system_private1"); + System.loadLibrary("systemext_private1"); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1")); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1")); + } + + @Test + public void testLoadExtendedPublicLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_extpub2.oem1"); + SystemSharedLib.loadLibrary("product_extpub2.product1"); + } + + @Test + public void testLoadPrivateLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_private2"); + SystemSharedLib.loadLibrary("systemext_private2"); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2")); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2")); + } + + @Test + public void testLoadPrivateLibrariesViaSystemExtSharedLib() { + SystemExtSharedLib.loadLibrary("system_private3"); + SystemExtSharedLib.loadLibrary("systemext_private3"); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3")); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3")); + } + + @Test + public void testLoadPrivateLibrariesViaProductSharedLib() { + ProductSharedLib.loadLibrary("system_private4"); + ProductSharedLib.loadLibrary("systemext_private4"); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("product_private4")); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("vendor_private4")); + } + + @Test + public void testLoadPrivateLibrariesViaVendorSharedLib() { + VendorSharedLib.loadLibrary("system_private5"); + VendorSharedLib.loadLibrary("systemext_private5"); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("product_private5")); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("vendor_private5")); + } + + @Test + public void testLoadExtendedPublicLibrariesWithAbsolutePaths() { + System.load(TestUtils.libPath("/system", "system_extpub3.oem1")); + System.load(TestUtils.libPath("/product", "product_extpub3.product1")); + } + + @Test + public void testLoadPrivateLibrariesWithAbsolutePaths() { + System.load(TestUtils.libPath("/system", "system_private6")); + System.load(TestUtils.libPath("/system_ext", "systemext_private6")); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/product", "product_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/vendor", "vendor_private6"))); + } +} diff --git a/libnativeloader/test/src/android/test/app/TestActivity.java b/libnativeloader/test/src/android/test/app/TestActivity.java deleted file mode 100644 index a7a455d33d..0000000000 --- a/libnativeloader/test/src/android/test/app/TestActivity.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2018 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.app.Activity; -import android.os.Bundle; -import android.util.Log; - -public class TestActivity extends Activity { - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - tryLoadingLib("foo.oem1"); - tryLoadingLib("bar.oem1"); - tryLoadingLib("foo.oem2"); - tryLoadingLib("bar.oem2"); - tryLoadingLib("foo.product1"); - tryLoadingLib("bar.product1"); - } - - private void tryLoadingLib(String name) { - try { - System.loadLibrary(name); - Log.d(getPackageName(), "library " + name + " is successfully loaded"); - } catch (UnsatisfiedLinkError e) { - Log.d(getPackageName(), "failed to load libarary " + name, e); - } - } -} diff --git a/libnativeloader/test/src/android/test/app/VendorAppTest.java b/libnativeloader/test/src/android/test/app/VendorAppTest.java new file mode 100644 index 0000000000..10d0ea04ee --- /dev/null +++ b/libnativeloader/test/src/android/test/app/VendorAppTest.java @@ -0,0 +1,111 @@ +/* + * 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 android.test.productsharedlib.ProductSharedLib; +import android.test.systemextsharedlib.SystemExtSharedLib; +import android.test.systemsharedlib.SystemSharedLib; +import android.test.vendorsharedlib.VendorSharedLib; +import androidx.test.filters.MediumTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +@MediumTest +@RunWith(AndroidJUnit4.class) +public class VendorAppTest { + @Test + public void testLoadExtendedPublicLibraries() { + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_extpub.oem1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_extpub.oem2")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_extpub1.oem1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_extpub_nouses.oem2")); + System.loadLibrary("product_extpub.product1"); + System.loadLibrary("product_extpub1.product1"); + } + + @Test + public void testLoadPrivateLibraries() { + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1")); + TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1")); + TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1")); + System.loadLibrary("vendor_private1"); + } + + @Test + public void testLoadExtendedPublicLibrariesViaSystemSharedLib() { + SystemSharedLib.loadLibrary("system_extpub2.oem1"); + SystemSharedLib.loadLibrary("product_extpub2.product1"); + } + + @Test + public void testLoadPrivateLibrariesViaSystemSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemSharedLib.loadLibrary("system_private2"); + // SystemSharedLib.loadLibrary("systemext_private2"); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2")); + TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2")); + } + + @Test + public void testLoadPrivateLibrariesViaSystemExtSharedLib() { + // TODO(b/237577392): Loading a private native system library via a shared system library + // ought to work. + // SystemExtSharedLib.loadLibrary("system_private3"); + // SystemExtSharedLib.loadLibrary("systemext_private3"); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3")); + TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3")); + } + + @Test + public void testLoadPrivateLibrariesViaProductSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> ProductSharedLib.loadLibrary("system_private4")); + TestUtils.assertLinkerNamespaceError( + () -> ProductSharedLib.loadLibrary("systemext_private4")); + ProductSharedLib.loadLibrary("product_private4"); + TestUtils.assertLibraryNotFound(() -> ProductSharedLib.loadLibrary("vendor_private4")); + } + + @Test + public void testLoadPrivateLibrariesViaVendorSharedLib() { + TestUtils.assertLinkerNamespaceError(() -> VendorSharedLib.loadLibrary("system_private5")); + TestUtils.assertLinkerNamespaceError( + () -> VendorSharedLib.loadLibrary("systemext_private5")); + TestUtils.assertLibraryNotFound(() -> VendorSharedLib.loadLibrary("product_private5")); + VendorSharedLib.loadLibrary("vendor_private5"); + } + + @Test + public void testLoadExtendedPublicLibrariesWithAbsolutePaths() { + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system", "system_extpub3.oem1"))); + System.load(TestUtils.libPath("/product", "product_extpub3.product1")); + } + + @Test + public void testLoadPrivateLibrariesWithAbsolutePaths() { + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system", "system_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/system_ext", "systemext_private6"))); + TestUtils.assertLinkerNamespaceError( + () -> System.load(TestUtils.libPath("/product", "product_private6"))); + System.load(TestUtils.libPath("/vendor", "vendor_private6")); + } +} diff --git a/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java new file mode 100644 index 0000000000..55a6dd27b3 --- /dev/null +++ b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java @@ -0,0 +1,388 @@ +/* + * 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.hostside; + +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; +import com.android.tradefed.invoker.TestInformation; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.IAbi; +import com.android.tradefed.testtype.junit4.AfterClassWithInfo; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.tradefed.testtype.junit4.BeforeClassWithInfo; +import com.android.tradefed.testtype.junit4.DeviceTestRunOptions; +import com.android.tradefed.util.CommandResult; + +import com.google.common.io.ByteStreams; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * Test libnativeloader behavior for apps and libs in various partitions by overlaying them over + * the system partitions. Requires root. + */ +@RunWith(DeviceJUnit4ClassRunner.class) +public class LibnativeloaderTest extends BaseHostJUnit4Test { + private static final String TAG = "LibnativeloaderTest"; + private static final String CLEANUP_PATHS_KEY = TAG + ":CLEANUP_PATHS"; + private static final String LOG_FILE_NAME = "TestActivity.log"; + + @BeforeClassWithInfo + public static void beforeClassWithDevice(TestInformation testInfo) throws Exception { + DeviceContext ctx = new DeviceContext(testInfo); + + // A soft reboot is slow, so do setup for all tests and reboot once. + + File libContainerApk = ctx.mBuildHelper.getTestFile("library_container_app.apk"); + try (ZipFile libApk = new ZipFile(libContainerApk)) { + ctx.pushExtendedPublicSystemOemLibs(libApk); + ctx.pushExtendedPublicProductLibs(libApk); + ctx.pushPrivateLibs(libApk); + } + ctx.pushSharedLib( + "/system", "android.test.systemsharedlib", "libnativeloader_system_shared_lib.jar"); + ctx.pushSharedLib("/system_ext", "android.test.systemextsharedlib", + "libnativeloader_system_ext_shared_lib.jar"); + ctx.pushSharedLib("/product", "android.test.productsharedlib", + "libnativeloader_product_shared_lib.jar"); + ctx.pushSharedLib( + "/vendor", "android.test.vendorsharedlib", "libnativeloader_vendor_shared_lib.jar"); + + // "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"); + + // For testSystemApp + ctx.pushApk("loadlibrarytest_system_app", "/system/app"); + + // For testSystemExtApp + ctx.pushApk("loadlibrarytest_system_ext_app", "/system_ext/app"); + + // For testProductApp + ctx.pushApk("loadlibrarytest_product_app", "/product/app"); + + // For testVendorApp + ctx.pushApk("loadlibrarytest_vendor_app", "/vendor/app"); + + 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 { + DeviceContext ctx = new DeviceContext(testInfo); + + // Uninstall loadlibrarytest_data_app. + ctx.mDevice.uninstallPackage("android.test.app.data"); + + String cleanupPathList = testInfo.properties().get(CLEANUP_PATHS_KEY); + CleanupPaths cleanup = new CleanupPaths(ctx.mDevice, cleanupPathList); + cleanup.cleanup(); + } + + @Test + public void testSystemPrivApp() throws Exception { + // There's currently no difference in the tests between /system/priv-app and /system/app, so + // let's reuse the same one. + runTests("android.test.app.system_priv", "android.test.app.SystemAppTest"); + } + + @Test + public void testSystemApp() throws Exception { + runTests("android.test.app.system", "android.test.app.SystemAppTest"); + } + + @Test + public void testSystemExtApp() throws Exception { + // /system_ext should behave the same as /system, so run the same test class there. + runTests("android.test.app.system_ext", "android.test.app.SystemAppTest"); + } + + @Test + public void testProductApp() throws Exception { + runTests("android.test.app.product", "android.test.app.ProductAppTest"); + } + + @Test + public void testVendorApp() throws Exception { + runTests("android.test.app.vendor", "android.test.app.VendorAppTest"); + } + + @Test + public void testDataApp() throws Exception { + runTests("android.test.app.data", "android.test.app.DataAppTest"); + } + + private void runTests(String pkgName, String testClassName) throws Exception { + DeviceContext ctx = new DeviceContext(getTestInformation()); + var options = new DeviceTestRunOptions(pkgName) + .setTestClassName(testClassName) + .addInstrumentationArg("libDirName", ctx.libDirName()); + runDeviceTests(options); + } + + // Utility class that keeps track of a set of paths the need to be deleted after testing. + private static class CleanupPaths { + private ITestDevice mDevice; + private List<String> mCleanupPaths; + + CleanupPaths(ITestDevice device) { + mDevice = device; + mCleanupPaths = new ArrayList<String>(); + } + + CleanupPaths(ITestDevice device, String pathList) { + mDevice = device; + mCleanupPaths = Arrays.asList(pathList.split(":")); + } + + String getPathList() { return String.join(":", mCleanupPaths); } + + // Adds the given path, or its topmost nonexisting parent directory, to the list of paths to + // clean up. + void addPath(String devicePath) throws DeviceNotAvailableException { + File path = new File(devicePath); + while (true) { + File parentPath = path.getParentFile(); + if (parentPath == null || mDevice.doesFileExist(parentPath.toString())) { + break; + } + path = parentPath; + } + String nonExistingPath = path.toString(); + if (!mCleanupPaths.contains(nonExistingPath)) { + mCleanupPaths.add(nonExistingPath); + } + } + + void cleanup() throws DeviceNotAvailableException { + // Clean up in reverse order in case several pushed files were in the same nonexisting + // directory. + for (int i = mCleanupPaths.size() - 1; i >= 0; --i) { + mDevice.deleteFile(mCleanupPaths.get(i)); + } + } + } + + // Class for code that needs an ITestDevice. It may be instantiated both in tests and in + // (Before|After)ClassWithInfo. + private static class DeviceContext implements AutoCloseable { + IInvocationContext mContext; + ITestDevice mDevice; + CompatibilityBuildHelper mBuildHelper; + CleanupPaths mCleanup; + private String mTestArch; + + DeviceContext(TestInformation testInfo) { + mContext = testInfo.getContext(); + mDevice = testInfo.getDevice(); + mBuildHelper = new CompatibilityBuildHelper(testInfo.getBuildInfo()); + mCleanup = new CleanupPaths(mDevice); + } + + public void close() throws DeviceNotAvailableException { mCleanup.cleanup(); } + + // Helper class to both push a library to device and record it in a public.libraries-xxx.txt + // file. + class PublicLibs { + private ZipFile mLibApk; + private List<String> mPublicLibs = new ArrayList<String>(); + + PublicLibs(ZipFile libApk) { + mLibApk = libApk; + } + + void addLib(String libName, String destDir, String destName) throws Exception { + pushNativeTestLib(mLibApk, libName, destDir + "/" + destName); + mPublicLibs.add(destName); + } + + void pushPublicLibrariesFile(String path) throws DeviceNotAvailableException { + pushString(mPublicLibs.stream().collect(Collectors.joining("\n")) + "\n", path); + } + } + + void pushExtendedPublicSystemOemLibs(ZipFile libApk) throws Exception { + var oem1Libs = new PublicLibs(libApk); + // Push libsystem_extpub<n>.oem1.so 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 <= 3; ++i) { + oem1Libs.addLib("libsystem_testlib.so", "/system/${LIB}", + "libsystem_extpub" + i + ".oem1.so"); + } + oem1Libs.addLib("libsystem_testlib.so", "/system/${LIB}", "libsystem_extpub.oem1.so"); + oem1Libs.pushPublicLibrariesFile("/system/etc/public.libraries-oem1.txt"); + + var oem2Libs = new PublicLibs(libApk); + oem2Libs.addLib("libsystem_testlib.so", "/system/${LIB}", "libsystem_extpub.oem2.so"); + // libextpub_nouses.oem2.so is a library that the test apps don't have + // <uses-native-library> dependencies for. + oem2Libs.addLib( + "libsystem_testlib.so", "/system/${LIB}", "libsystem_extpub_nouses.oem2.so"); + oem2Libs.pushPublicLibrariesFile("/system/etc/public.libraries-oem2.txt"); + } + + void pushExtendedPublicProductLibs(ZipFile libApk) throws Exception { + var product1Libs = new PublicLibs(libApk); + // Push libproduct_extpub<n>.product1.so 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 <= 3; ++i) { + product1Libs.addLib("libproduct_testlib.so", "/product/${LIB}", + "libproduct_extpub" + i + ".product1.so"); + } + product1Libs.addLib( + "libproduct_testlib.so", "/product/${LIB}", "libproduct_extpub.product1.so"); + product1Libs.pushPublicLibrariesFile("/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 <= 6; ++i) { + pushNativeTestLib(libApk, "libsystem_testlib.so", + "/system/${LIB}/libsystem_private" + i + ".so"); + pushNativeTestLib(libApk, "libsystem_testlib.so", + "/system_ext/${LIB}/libsystemext_private" + i + ".so"); + pushNativeTestLib(libApk, "libproduct_testlib.so", + "/product/${LIB}/libproduct_private" + i + ".so"); + pushNativeTestLib(libApk, "libvendor_testlib.so", + "/vendor/${LIB}/libvendor_private" + i + ".so"); + } + } + + void pushSharedLib(String partitionDir, String packageName, String buildJarName) + throws Exception { + String path = partitionDir + "/framework/" + packageName + ".jar"; + pushFile(buildJarName, path); + // This permissions xml file is necessary to make it possible to depend on the shared + // library from the test app, even if it's in the same partition. It makes the library + // public to apps in other partitions as well, which is more than we need, but that + // being the case we test all shared libraries from all apps. + pushString("<permissions>\n" + + "<library name=\"" + packageName + "\" file=\"" + path + "\" />\n" + + "</permissions>\n", + partitionDir + "/etc/permissions/" + packageName + ".xml"); + } + + void softReboot() throws DeviceNotAvailableException { + assertCommandSucceeds("setprop dev.bootcomplete 0"); + assertCommandSucceeds("stop"); + assertCommandSucceeds("start"); + mDevice.waitForDeviceAvailable(); + } + + String getTestArch() throws DeviceNotAvailableException { + if (mTestArch == null) { + IAbi abi = mContext.getConfigurationDescriptor().getAbi(); + mTestArch = abi != null ? abi.getName() + : assertCommandSucceeds("getprop ro.product.cpu.abi"); + } + return mTestArch; + } + + String libDirName() throws DeviceNotAvailableException { + return getTestArch().contains("64") ? "lib64" : "lib"; + } + + // Pushes the given file contents to the device at the given destination path. destPath is + // assumed to have no risk of overlapping with existing files, and is deleted in tearDown(), + // along with any directory levels that had to be created. + void pushString(String fileContents, String destPath) throws DeviceNotAvailableException { + mCleanup.addPath(destPath); + assertThat(mDevice.pushString(fileContents, destPath)).isTrue(); + } + + // 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(mBuildHelper.getTestFile(fileName), destPath)).isTrue(); + } + + void pushApk(String apkBaseName, String destPath) throws Exception { + pushFile(apkBaseName + ".apk", + destPath + "/" + apkBaseName + "/" + apkBaseName + ".apk"); + } + + // Like pushString, but extracts libnativeloader_testlib.so from the library_container_app + // APK and pushes it to destPath. "${LIB}" is replaced with "lib" or "lib64" as appropriate. + void pushNativeTestLib(ZipFile libApk, String libName, String destPath) throws Exception { + String libApkPath = "lib/" + getTestArch() + "/" + libName; + ZipEntry entry = libApk.getEntry(libApkPath); + assertWithMessage("Failed to find " + libApkPath + " in library_container_app.apk") + .that(entry) + .isNotNull(); + + File libraryTempFile; + try (InputStream inStream = libApk.getInputStream(entry)) { + libraryTempFile = writeStreamToTempFile(libName, inStream); + } + + destPath = destPath.replace("${LIB}", libDirName()); + + mCleanup.addPath(destPath); + 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); + // Remove trailing \n's. + return result.getStdout().trim(); + } + } + + static private File writeStreamToTempFile(String tempFileBaseName, InputStream inStream) + throws Exception { + File hostTempFile = File.createTempFile(tempFileBaseName, null); + try (FileOutputStream outStream = new FileOutputStream(hostTempFile)) { + ByteStreams.copy(inStream, outStream); + } + return hostTempFile; + } +} diff --git a/libnativeloader/test/src/android/test/lib/TestUtils.java b/libnativeloader/test/src/android/test/lib/TestUtils.java new file mode 100644 index 0000000000..1dd917f89f --- /dev/null +++ b/libnativeloader/test/src/android/test/lib/TestUtils.java @@ -0,0 +1,41 @@ +/* + * 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.lib; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import androidx.test.platform.app.InstrumentationRegistry; +import org.junit.function.ThrowingRunnable; + +public final class TestUtils { + 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"); + } + + public static String libPath(String dir, String libName) { + String libDirName = InstrumentationRegistry.getArguments().getString("libDirName"); + return dir + "/" + libDirName + "/lib" + libName + ".so"; + } +} diff --git a/libnativeloader/test/test.cpp b/libnativeloader/test/src/android/test/productsharedlib/ProductSharedLib.java index b166928f0e..a500d2a976 100644 --- a/libnativeloader/test/test.cpp +++ b/libnativeloader/test/src/android/test/productsharedlib/ProductSharedLib.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#define LOG_TAG "oemlib" -#include <android-base/logging.h> -static __attribute__((constructor)) void test_lib_init() { - LOG(DEBUG) << LIBNAME << " loaded"; +package android.test.productsharedlib; + +public final class ProductSharedLib { + public static void loadLibrary(String name) { System.loadLibrary(name); } } diff --git a/libnativeloader/test/vendor/AndroidManifest.xml b/libnativeloader/test/src/android/test/systemextsharedlib/SystemExtSharedLib.java index c4c1a9c210..1240e12e55 100644 --- a/libnativeloader/test/vendor/AndroidManifest.xml +++ b/libnativeloader/test/src/android/test/systemextsharedlib/SystemExtSharedLib.java @@ -1,6 +1,5 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - * Copyright (C) 2018 The Android Open Source Project +/* + * 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. @@ -13,19 +12,10 @@ * 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.vendor"> - - <application> - <activity android:name="android.test.app.TestActivity" > - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> - -</manifest> +package android.test.systemextsharedlib; +public final class SystemExtSharedLib { + public static void loadLibrary(String name) { System.loadLibrary(name); } +} 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 0000000000..8e2af9f79c --- /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); } +} diff --git a/libnativeloader/test/src/android/test/vendorsharedlib/VendorSharedLib.java b/libnativeloader/test/src/android/test/vendorsharedlib/VendorSharedLib.java new file mode 100644 index 0000000000..8859b63db4 --- /dev/null +++ b/libnativeloader/test/src/android/test/vendorsharedlib/VendorSharedLib.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.vendorsharedlib; + +public final class VendorSharedLib { + public static void loadLibrary(String name) { System.loadLibrary(name); } +} |