diff options
29 files changed, 754 insertions, 258 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING index 300526faa9..ec814ef614 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1283,6 +1283,9 @@ "name": "art_standalone_sigchain_tests[com.google.android.art.apex]" }, { + "name": "libnativeloader_e2e_tests[com.google.android.art.apex]" + }, + { "name": "libnativeloader_test[com.google.android.art.apex]" } ], @@ -2584,6 +2587,9 @@ "name": "art_standalone_sigchain_tests" }, { + "name": "libnativeloader_e2e_tests" + }, + { "name": "libnativeloader_test" } ] diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 7002636d4e..e578d3bf7f 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -85,7 +85,7 @@ void JitCompiler::ParseCompilerOptions() { if (StartsWith(option, "--instruction-set-variant=")) { const char* str = option.c_str() + strlen("--instruction-set-variant="); VLOG(compiler) << "JIT instruction set variant " << str; - instruction_set_features = InstructionSetFeatures::FromVariant( + instruction_set_features = InstructionSetFeatures::FromVariantAndHwcap( instruction_set, str, &error_msg); if (instruction_set_features == nullptr) { LOG(WARNING) << "Error parsing " << option << " message=" << error_msg; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 9e6103b424..27bae654c3 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -607,8 +607,13 @@ class Dex2Oat final { } void ParseInstructionSetVariant(const std::string& option, ParserOptions* parser_options) { - compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariant( - compiler_options_->instruction_set_, option, &parser_options->error_msg); + if (kIsTargetBuild) { + compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariantAndHwcap( + compiler_options_->instruction_set_, option, &parser_options->error_msg); + } else { + compiler_options_->instruction_set_features_ = InstructionSetFeatures::FromVariant( + compiler_options_->instruction_set_, option, &parser_options->error_msg); + } if (compiler_options_->instruction_set_features_ == nullptr) { Usage("%s", parser_options->error_msg.c_str()); } diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp index b787fbabb6..57d26c0316 100644 --- a/libnativebridge/tests/Android.bp +++ b/libnativebridge/tests/Android.bp @@ -110,6 +110,14 @@ cc_test { // unloading, so each test needs to be its own process. test_per_src: true, + // Disable pre-submit host unit-testing for this test module, as + // it is not compatible with TradeFed (because of the use of the + // `test_per_src` feature above) and meant to be executed with the + // `runtests.sh` script instead. + test_options: { + unit_test: false, + }, + srcs: [ "NativeBridgeApi.c", "CodeCacheCreate_test.cpp", diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index f31c4302a4..96d4ddeac6 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -231,51 +231,38 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t std::string system_exposed_libraries = default_public_libraries(); std::string namespace_name = kClassloaderNamespaceName; ApkOrigin unbundled_app_origin = APK_ORIGIN_DEFAULT; - if ((apk_origin == APK_ORIGIN_VENDOR || - (apk_origin == APK_ORIGIN_PRODUCT && - is_product_vndk_version_defined())) && - !is_shared) { - unbundled_app_origin = apk_origin; - // For vendor / product apks, give access to the vendor / product lib even though - // they are treated as unbundled; the libs and apks are still bundled - // together in the vendor / product partition. - const char* origin_partition; - const char* origin_lib_path; - const char* llndk_libraries; - - switch (apk_origin) { - case APK_ORIGIN_VENDOR: - origin_partition = "vendor"; - origin_lib_path = kVendorLibPath; - llndk_libraries = llndk_libraries_vendor().c_str(); - break; - case APK_ORIGIN_PRODUCT: - origin_partition = "product"; - origin_lib_path = kProductLibPath; - llndk_libraries = llndk_libraries_product().c_str(); - break; - default: - origin_partition = "unknown"; - origin_lib_path = ""; - llndk_libraries = ""; - } - library_path = library_path + ":" + origin_lib_path; - permitted_path = permitted_path + ":" + origin_lib_path; - - // Also give access to LLNDK libraries since they are available to vendor or product - system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries; - - // Different name is useful for debugging - namespace_name = kVendorClassloaderNamespaceName; - ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s", - origin_partition, library_path.c_str()); - } else { - auto libs = filter_public_libraries(target_sdk_version, uses_libraries, - extended_public_libraries()); - // extended public libraries are NOT available to vendor apks, otherwise it - // would be system->vendor violation. - if (!libs.empty()) { - system_exposed_libraries = system_exposed_libraries + ':' + libs; + const char* apk_origin_msg = "other apk"; // Only for debug logging. + + if (!is_shared) { + if (apk_origin == APK_ORIGIN_VENDOR) { + unbundled_app_origin = APK_ORIGIN_VENDOR; + apk_origin_msg = "unbundled vendor apk"; + + // For vendor apks, give access to the vendor libs even though they are + // treated as unbundled; the libs and apks are still bundled together in the + // vendor partition. + library_path = library_path + ':' + kVendorLibPath; + permitted_path = permitted_path + ':' + kVendorLibPath; + + // Also give access to LLNDK libraries since they are available to vendor. + system_exposed_libraries = system_exposed_libraries + ':' + llndk_libraries_vendor(); + + // Different name is useful for debugging + namespace_name = kVendorClassloaderNamespaceName; + } else if (apk_origin == APK_ORIGIN_PRODUCT && is_product_vndk_version_defined()) { + unbundled_app_origin = APK_ORIGIN_PRODUCT; + apk_origin_msg = "unbundled product apk"; + + // Like for vendor apks, give access to the product libs since they are + // bundled together in the same partition. + library_path = library_path + ':' + kProductLibPath; + permitted_path = permitted_path + ':' + kProductLibPath; + + // Also give access to LLNDK libraries since they are available to product. + system_exposed_libraries = system_exposed_libraries + ':' + llndk_libraries_product(); + + // Different name is useful for debugging + namespace_name = kVendorClassloaderNamespaceName; } } @@ -285,6 +272,32 @@ Result<NativeLoaderNamespace*> LibraryNamespaces::Create(JNIEnv* env, uint32_t t namespace_name = namespace_name + kSharedNamespaceSuffix; } + ALOGD( + "Configuring %s for %s %s. target_sdk_version=%u, uses_libraries=%s, library_path=%s, " + "permitted_path=%s", + namespace_name.c_str(), + apk_origin_msg, + dex_path.c_str(), + static_cast<unsigned>(target_sdk_version), + android::base::Join(uses_libraries, ':').c_str(), + library_path.c_str(), + permitted_path.c_str()); + + if (unbundled_app_origin != APK_ORIGIN_VENDOR) { + // Extended public libraries are NOT available to unbundled vendor apks, but + // they are to other apps, including those in system, system_ext, and + // product partitions. The reason is that when GSI is used, the system + // partition may get replaced, and then vendor apps may fail. It's fine for + // product (and system_ext) apps, because those partitions aren't mounted in + // GSI tests. + auto libs = + filter_public_libraries(target_sdk_version, uses_libraries, extended_public_libraries()); + if (!libs.empty()) { + ALOGD("Extending system_exposed_libraries: %s", libs.c_str()); + system_exposed_libraries = system_exposed_libraries + ':' + libs; + } + } + // Create the app namespace NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader); // Heuristic: the first classloader with non-empty library_path is assumed to diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp index fb9ae0d9d3..dd5e969dd1 100644 --- a/libnativeloader/test/Android.bp +++ b/libnativeloader/test/Android.bp @@ -24,57 +24,88 @@ package { } cc_library { - name: "libfoo.oem1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.oem1.so\""], - shared_libs: [ - "libbase", - ], + name: "libnativeloader_testlib", + srcs: [], + stl: "none", } -cc_library { - name: "libbar.oem1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.oem1.so\""], - shared_libs: [ - "libbase", - ], +// 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. +android_test_helper_app { + name: "library_container_app", + defaults: ["art_module_source_build_java_defaults"], + manifest: "library_container_app_manifest.xml", + compile_multilib: "both", + jni_libs: ["libnativeloader_testlib"], } -cc_library { - name: "libfoo.oem2", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.oem2.so\""], - shared_libs: [ - "libbase", +java_defaults { + name: "loadlibrarytest_app_defaults", + defaults: ["art_module_source_build_java_defaults"], + + // TODO(mast): Use old target SDK to avoid filtering on uses_library lists. + // Figure out what we need to do to make <uses-native-library> work in the + // test apps so we can use that instead. + sdk_version: "30", + + static_libs: [ + "androidx.test.ext.junit", + "androidx.test.ext.truth", + "androidx.test.rules", ], } -cc_library { - name: "libbar.oem2", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.oem2.so\""], - shared_libs: [ - "libbase", - ], +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"], } -cc_library { - name: "libfoo.product1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libfoo.product1.so\""], - product_specific: true, - shared_libs: [ - "libbase", - ], +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"], } -cc_library { - name: "libbar.product1", - srcs: ["test.cpp"], - cflags: ["-DLIBNAME=\"libbar.product1.so\""], - product_specific: true, - shared_libs: [ - "libbase", +android_test_helper_app { + name: "loadlibrarytest_system_ext_app", + defaults: ["loadlibrarytest_app_defaults"], + 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"], + 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"], + manifest: "loadlibrarytest_vendor_app_manifest.xml", + srcs: ["src/android/test/app/VendorAppTest.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: [ + ":library_container_app", + ":loadlibrarytest_system_priv_app", + ":loadlibrarytest_system_app", + ":loadlibrarytest_system_ext_app", + ":loadlibrarytest_product_app", + ":loadlibrarytest_vendor_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..b1333b0765 --- /dev/null +++ b/libnativeloader/test/libnativeloader_e2e_tests.xml @@ -0,0 +1,28 @@ +<?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" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" /> + + <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/test.cpp b/libnativeloader/test/library_container_app_manifest.xml index b166928f0e..20030de7eb 100644 --- a/libnativeloader/test/test.cpp +++ b/libnativeloader/test/library_container_app_manifest.xml @@ -1,5 +1,6 @@ -/* - * Copyright (C) 2017 The Android Open Source Project +<?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. @@ -12,10 +13,8 @@ * 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. - */ -#define LOG_TAG "oemlib" -#include <android-base/logging.h> + --> -static __attribute__((constructor)) void test_lib_init() { - LOG(DEBUG) << LIBNAME << " loaded"; -} +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.test.app.container"> +</manifest> diff --git a/libnativeloader/test/system/AndroidManifest.xml b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml index c3048891a8..a791795803 100644 --- a/libnativeloader/test/system/AndroidManifest.xml +++ b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml @@ -16,16 +16,8 @@ --> <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.product"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.product" /> </manifest> diff --git a/libnativeloader/test/vendor/AndroidManifest.xml b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml index c4c1a9c210..3cbd054f03 100644 --- a/libnativeloader/test/vendor/AndroidManifest.xml +++ b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml @@ -16,16 +16,8 @@ --> <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> - + package="android.test.app.system"> + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.test.app.system" /> </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..83ca779821 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml @@ -0,0 +1,23 @@ +<?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" /> +</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..0ad1aa5e32 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml @@ -0,0 +1,23 @@ +<?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" /> +</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..b7073c6302 --- /dev/null +++ b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml @@ -0,0 +1,23 @@ +<?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" /> +</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/ProductAppTest.java b/libnativeloader/test/src/android/test/app/ProductAppTest.java new file mode 100644 index 0000000000..243e2c750d --- /dev/null +++ b/libnativeloader/test/src/android/test/app/ProductAppTest.java @@ -0,0 +1,39 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +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 ProductAppTest { + @Test + public void testLoadLibraries() { + System.loadLibrary("foo.oem1"); + System.loadLibrary("bar.oem1"); + System.loadLibrary("foo.oem2"); + System.loadLibrary("bar.oem2"); + 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 new file mode 100644 index 0000000000..dd680f5bd1 --- /dev/null +++ b/libnativeloader/test/src/android/test/app/SystemAppTest.java @@ -0,0 +1,40 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +// These tests are run in both /system and /system_ext. +@SmallTest +@RunWith(AndroidJUnit4.class) +public class SystemAppTest { + @Test + public void testLoadLibraries() { + System.loadLibrary("foo.oem1"); + System.loadLibrary("bar.oem1"); + System.loadLibrary("foo.oem2"); + System.loadLibrary("bar.oem2"); + System.loadLibrary("foo.product1"); + System.loadLibrary("bar.product1"); + } +} 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..a830d06293 --- /dev/null +++ b/libnativeloader/test/src/android/test/app/VendorAppTest.java @@ -0,0 +1,46 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +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 VendorAppTest { + @Test + public void testLoadLibraries() { + assertLinkerNamespaceError("foo.oem1"); + assertLinkerNamespaceError("bar.oem1"); + assertLinkerNamespaceError("foo.oem2"); + assertLinkerNamespaceError("bar.oem2"); + System.loadLibrary("foo.product1"); + System.loadLibrary("bar.product1"); + } + + private void assertLinkerNamespaceError(String libraryName) { + Throwable t = + assertThrows(UnsatisfiedLinkError.class, () -> System.loadLibrary(libraryName)); + assertThat(t.getMessage()) + .containsMatch("dlopen failed: .* is not accessible for the namespace"); + } +} 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..7e2d9de35c --- /dev/null +++ b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java @@ -0,0 +1,294 @@ +/* + * 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.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.util.CommandResult; +import com.google.common.io.ByteStreams; +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.zip.ZipEntry; +import java.util.zip.ZipFile; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * 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.getContext(), testInfo.getDevice()); + + // A soft reboot is slow, so do setup for all tests and reboot once. + + ctx.mDevice.remountSystemWritable(); + try (ZipFile libApk = openLibContainerApk()) { + 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. + + // 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(); + + testInfo.properties().put(CLEANUP_PATHS_KEY, ctx.mCleanup.getPathList()); + } + + @AfterClassWithInfo + public static void afterClassWithDevice(TestInformation testInfo) throws Exception { + String cleanupPathList = testInfo.properties().get(CLEANUP_PATHS_KEY); + CleanupPaths cleanup = new CleanupPaths(testInfo.getDevice(), 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. + runDeviceTests("android.test.app.system_priv", "android.test.app.SystemAppTest"); + } + + @Test + public void testSystemApp() throws Exception { + runDeviceTests("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. + runDeviceTests("android.test.app.system_ext", "android.test.app.SystemAppTest"); + } + + @Test + public void testProductApp() throws Exception { + runDeviceTests("android.test.app.product", "android.test.app.ProductAppTest"); + } + + @Test + public void testVendorApp() throws Exception { + runDeviceTests("android.test.app.vendor", "android.test.app.VendorAppTest"); + } + + // 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 is instantiated both in tests and in + // (Before|After)ClassWithInfo. + private static class DeviceContext implements AutoCloseable { + IInvocationContext mContext; + ITestDevice mDevice; + CleanupPaths mCleanup; + private String mTestArch; + + DeviceContext(IInvocationContext context, ITestDevice device) { + mContext = context; + mDevice = device; + mCleanup = new CleanupPaths(mDevice); + } + + public void close() throws DeviceNotAvailableException { mCleanup.cleanup(); } + + void pushSystemOemLibs(ZipFile libApk) throws Exception { + pushNativeTestLib(libApk, "/system/${LIB}/libfoo.oem1.so"); + pushNativeTestLib(libApk, "/system/${LIB}/libbar.oem1.so"); + pushString("libfoo.oem1.so\n" + + "libbar.oem1.so\n", + "/system/etc/public.libraries-oem1.txt"); + + pushNativeTestLib(libApk, "/system/${LIB}/libfoo.oem2.so"); + pushNativeTestLib(libApk, "/system/${LIB}/libbar.oem2.so"); + pushString("libfoo.oem2.so\n" + + "libbar.oem2.so\n", + "/system/etc/public.libraries-oem2.txt"); + } + + void pushProductLibs(ZipFile libApk) throws Exception { + pushNativeTestLib(libApk, "/product/${LIB}/libfoo.product1.so"); + pushNativeTestLib(libApk, "/product/${LIB}/libbar.product1.so"); + pushString("libfoo.product1.so\n" + + "libbar.product1.so\n", + "/product/etc/public.libraries-product1.txt"); + } + + 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.bionic.arch"); + } + return mTestArch; + } + + // 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 extracts a Java resource and pushes that. + void pushResource(String resourceName, String destPath) throws Exception { + File hostTempFile = extractResourceToTempFile(resourceName); + mCleanup.addPath(destPath); + assertThat(mDevice.pushFile(hostTempFile, destPath)).isTrue(); + } + + void pushApk(String apkBaseName, String destPath) throws Exception { + pushResource("/" + 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 destPath) throws Exception { + String libApkPath = "lib/" + getTestArch() + "/libnativeloader_testlib.so"; + 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("libnativeloader_testlib.so", inStream); + } + + String libDir = getTestArch().contains("64") ? "lib64" : "lib"; + destPath = destPath.replace("${LIB}", libDir); + + mCleanup.addPath(destPath); + assertThat(mDevice.pushFile(libraryTempFile, destPath)).isTrue(); + } + + 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 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); + try (FileOutputStream outStream = new FileOutputStream(hostTempFile)) { + ByteStreams.copy(inStream, outStream); + } + return hostTempFile; + } +} diff --git a/runtime/arch/arm64/instruction_set_features_arm64.cc b/runtime/arch/arm64/instruction_set_features_arm64.cc index ad082aed1f..93400d9c7c 100644 --- a/runtime/arch/arm64/instruction_set_features_arm64.cc +++ b/runtime/arch/arm64/instruction_set_features_arm64.cc @@ -171,6 +171,18 @@ Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromVariant( has_sve)); } +Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::IntersectWithHwcap() const { + Arm64FeaturesUniquePtr hwcaps = Arm64InstructionSetFeatures::FromHwcap(); + return Arm64FeaturesUniquePtr(new Arm64InstructionSetFeatures( + fix_cortex_a53_835769_, + fix_cortex_a53_843419_, + has_crc_ && hwcaps->has_crc_, + has_lse_ && hwcaps->has_lse_, + has_fp16_ && hwcaps->has_fp16_, + has_dotprod_ && hwcaps->has_dotprod_, + has_sve_ && hwcaps->has_sve_)); +} + Arm64FeaturesUniquePtr Arm64InstructionSetFeatures::FromBitmap(uint32_t bitmap) { bool is_a53 = (bitmap & kA53Bitfield) != 0; bool has_crc = (bitmap & kCRCBitField) != 0; diff --git a/runtime/arch/arm64/instruction_set_features_arm64.h b/runtime/arch/arm64/instruction_set_features_arm64.h index eb98c01633..8f0013ac86 100644 --- a/runtime/arch/arm64/instruction_set_features_arm64.h +++ b/runtime/arch/arm64/instruction_set_features_arm64.h @@ -53,6 +53,10 @@ class Arm64InstructionSetFeatures final : public InstructionSetFeatures { // Use external cpu_features library. static Arm64FeaturesUniquePtr FromCpuFeatures(); + // Return a new set of instruction set features, intersecting `this` features + // with hardware capabilities. + Arm64FeaturesUniquePtr IntersectWithHwcap() const; + bool Equals(const InstructionSetFeatures* other) const override; // Note that newer CPUs do not have a53 erratum 835769 and 843419, diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc index ec1e340245..7a1e6b05ad 100644 --- a/runtime/arch/instruction_set_features.cc +++ b/runtime/arch/instruction_set_features.cc @@ -53,6 +53,33 @@ std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromVarian UNREACHABLE(); } +std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromVariantAndHwcap( + InstructionSet isa, const std::string& variant, std::string* error_msg) { + auto variant_features = FromVariant(isa, variant, error_msg); + if (variant_features == nullptr) { + return nullptr; + } + // Pixel3a is wrongly reporting itself as cortex-a75, so validate the features + // with hwcaps. + // Note that when cross-compiling on device (using dex2oat32 for compiling + // arm64), the hwcaps will report that no feature is supported. This is + // currently our best approach to be safe/correct. Maybe using the + // cpu_features library could fix this issue. + if (isa == InstructionSet::kArm64) { + auto new_features = down_cast<const Arm64InstructionSetFeatures*>(variant_features.get()) + ->IntersectWithHwcap(); + if (!variant_features->Equals(new_features.get())) { + LOG(WARNING) << "Mismatch between instruction set variant of device (" + << *variant_features + << ") and features returned by the hardware (" << *new_features << ")"; + } + return new_features; + } else { + // TODO: Implement this validation on all architectures. + return variant_features; + } +} + std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromBitmap(InstructionSet isa, uint32_t bitmap) { std::unique_ptr<const InstructionSetFeatures> result; diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h index b80d36f153..cee8c5d42f 100644 --- a/runtime/arch/instruction_set_features.h +++ b/runtime/arch/instruction_set_features.h @@ -39,6 +39,12 @@ class InstructionSetFeatures { const std::string& variant, std::string* error_msg); + // Process a CPU variant string for the given ISA and make sure the features advertised + // are supported by the hardware. This is needed for Pixel3a which wrongly + // reports itself as cortex-a75. + static std::unique_ptr<const InstructionSetFeatures> FromVariantAndHwcap( + InstructionSet isa, const std::string& variant, std::string* error_msg); + // Parse a bitmap for the given isa and create an InstructionSetFeatures. static std::unique_ptr<const InstructionSetFeatures> FromBitmap(InstructionSet isa, uint32_t bitmap); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 6afd63e4a5..4deb089349 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -1922,12 +1922,29 @@ bool ImageSpace::BootImageLayout::ReadHeader(const std::string& base_location, return false; } - // Validate oat files. We do it here so that the boot image will be re-compiled in memory if it's - // outdated. - size_t component_count = (header.GetImageSpaceCount() == 1u) ? header.GetComponentCount() : 1u; - for (size_t i = 0; i < header.GetImageSpaceCount(); i++) { - if (!ValidateOatFile(base_location, base_filename, bcp_index + i, component_count, error_msg)) { - return false; + bool validate_oat_files = true; + Runtime* runtime = Runtime::Current(); + if (runtime != nullptr && runtime->GetHeap() != nullptr) { + for (const ImageSpace* image_space : runtime->GetHeap()->GetBootImageSpaces()) { + if (image_space->GetComponentCount() == header.GetImageSpaceCount() && + image_space->GetImageHeader().GetImageChecksum() == header.GetImageChecksum()) { + // This image has been loaded by the runtime, meaning that the oat files were validated when + // the runtime loaded them, so we don't have to validate them again. + validate_oat_files = false; + break; + } + } + } + + if (validate_oat_files) { + // Validate oat files. We do it here so that the boot image will be re-compiled in memory if + // it's outdated. + size_t component_count = (header.GetImageSpaceCount() == 1u) ? header.GetComponentCount() : 1u; + for (size_t i = 0; i < header.GetImageSpaceCount(); i++) { + if (!ValidateOatFile( + base_location, base_filename, bcp_index + i, component_count, error_msg)) { + return false; + } } } diff --git a/test/utils/regen-test-files b/test/utils/regen-test-files index edf6dd127d..ebe25205d6 100755 --- a/test/utils/regen-test-files +++ b/test/utils/regen-test-files @@ -230,6 +230,7 @@ art_gtest_user_module_names = [ # ART gtests that need root access to the device. art_gtest_eng_only_module_names = [ + "libnativeloader_e2e_tests", "art_standalone_dexoptanalyzer_tests", "art_standalone_profman_tests", ] |