summaryrefslogtreecommitdiff
path: root/runtime/hidden_api_test.cc
diff options
context:
space:
mode:
author David Brazdil <dbrazdil@google.com> 2019-03-08 14:59:41 +0000
committer David Brazdil <dbrazdil@google.com> 2019-03-14 14:34:20 +0000
commita5c3a808020d81447bc19d07a99288e9d28a6e6c (patch)
tree83a9b1eac0a7209e6e407c0462d0b1ba8f95f62c /runtime/hidden_api_test.cc
parent98fb083a30e9b37685f943e2923e65e60e0a0971 (diff)
hiddenapi domain: Use oat dex file location if available
To determine the caller and callee domains of a hidden API access check, the logic will test the dex location against several known system locations. However, DexFile instances backed by an OatFile have relative dex locations to avoid need to rewrite the .oat file when moving files between folders. The canonical dex location is stored in the OatDexFile instead. Because the OatDexFile data structure is not available in libdexfile, move the domain resolution logic to hidden_api.cc and resolve when dex files is first registered with the class linker. Test: m test-art-gtest Test: camera does not crash Bug: 126901248 Bug: 127852529 Change-Id: Id494b1c47a2199c227dec046174e08320b9cbc3b
Diffstat (limited to 'runtime/hidden_api_test.cc')
-rw-r--r--runtime/hidden_api_test.cc210
1 files changed, 210 insertions, 0 deletions
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index cfc3b07300..be6407963b 100644
--- a/runtime/hidden_api_test.cc
+++ b/runtime/hidden_api_test.cc
@@ -16,10 +16,15 @@
#include "hidden_api.h"
+#include <fstream>
+
+#include "base/file_utils.h"
#include "base/sdk_version.h"
+#include "base/stl_util.h"
#include "common_runtime_test.h"
#include "jni/jni_internal.h"
#include "proxy_test.h"
+#include "well_known_classes.h"
namespace art {
@@ -375,4 +380,209 @@ TEST_F(HiddenApiTest, CheckMemberSignatureForProxyClass) {
ASSERT_EQ("L$Proxy1234;->interfaces:[Ljava/lang/Class;", ss_field.str());
}
+static bool Copy(const std::string& src, const std::string& dst, /*out*/ std::string* error_msg) {
+ std::ifstream src_stream(src, std::ios::binary);
+ std::ofstream dst_stream(dst, std::ios::binary);
+ dst_stream << src_stream.rdbuf();
+ src_stream.close();
+ dst_stream.close();
+ if (src_stream.good() && dst_stream.good()) {
+ return true;
+ } else {
+ *error_msg = "Copy " + src + " => " + dst + " (src_good="
+ + (src_stream.good() ? "true" : "false") + ", dst_good="
+ + (dst_stream.good() ? "true" : "false") + ")";
+ return false;
+ }
+}
+
+static bool LoadDexFiles(const std::string& path,
+ ScopedObjectAccess& soa,
+ /* out */ std::vector<std::unique_ptr<const DexFile>>* dex_files,
+ /* out */ ObjPtr<mirror::ClassLoader>* class_loader,
+ /* out */ std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!ArtDexFileLoader().Open(path.c_str(),
+ path,
+ /* verify= */ true,
+ /* verify_checksum= */ true,
+ error_msg,
+ dex_files)) {
+ return false;
+ }
+
+ ClassLinker* const linker = Runtime::Current()->GetClassLinker();
+
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::Class> h_class = hs.NewHandle(soa.Decode<mirror::Class>(
+ WellKnownClasses::dalvik_system_PathClassLoader));
+ Handle<mirror::ClassLoader> h_loader = hs.NewHandle(linker->CreateWellKnownClassLoader(
+ soa.Self(),
+ MakeNonOwningPointerVector(*dex_files),
+ h_class,
+ /* parent_loader= */ ScopedNullHandle<mirror::ClassLoader>(),
+ /* shared_libraries= */ ScopedNullHandle<mirror::ObjectArray<mirror::ClassLoader>>()));
+ for (const auto& dex_file : *dex_files) {
+ linker->RegisterDexFile(*dex_file.get(), h_loader.Get());
+ }
+
+ *class_loader = h_loader.Get();
+ return true;
+}
+
+static bool CheckAllDexFilesInDomain(ObjPtr<mirror::ClassLoader> loader,
+ const std::vector<std::unique_ptr<const DexFile>>& dex_files,
+ hiddenapi::Domain expected_domain)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ for (const auto& dex_file : dex_files) {
+ hiddenapi::AccessContext context(loader, dex_file.get());
+ if (context.GetDomain() != expected_domain) {
+ LOG(ERROR) << dex_file->GetLocation() << ": access context domain does not match "
+ << "(expected=" << static_cast<uint32_t>(expected_domain)
+ << ", actual=" << static_cast<uint32_t>(context.GetDomain()) << ")";
+ return false;
+ }
+ if (dex_file->GetHiddenapiDomain() != expected_domain) {
+ LOG(ERROR) << dex_file->GetLocation() << ": dex file domain does not match "
+ << "(expected=" << static_cast<uint32_t>(expected_domain)
+ << ", actual=" << static_cast<uint32_t>(dex_file->GetHiddenapiDomain()) << ")";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+TEST_F(HiddenApiTest, DexDomain_DataDir) {
+ // Load file from a non-system directory and check that it is not flagged as framework.
+ std::string data_location_path = android_data_ + "/foo.jar";
+ ASSERT_FALSE(LocationIsOnSystemFramework(data_location_path.c_str()));
+
+ ScopedObjectAccess soa(Thread::Current());
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ std::string error_msg;
+ ObjPtr<mirror::ClassLoader> class_loader;
+
+ ASSERT_TRUE(Copy(GetTestDexFileName("Main"), data_location_path, &error_msg)) << error_msg;
+ ASSERT_TRUE(LoadDexFiles(data_location_path, soa, &dex_files, &class_loader, &error_msg))
+ << error_msg;
+ ASSERT_GE(dex_files.size(), 1u);
+ ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kApplication));
+
+ dex_files.clear();
+ ASSERT_EQ(0, remove(data_location_path.c_str()));
+}
+
+TEST_F(HiddenApiTest, DexDomain_SystemDir) {
+ // Load file from a system, non-framework directory and check that it is not flagged as framework.
+ std::string system_location_path = GetAndroidRoot() + "/foo.jar";
+ ASSERT_FALSE(LocationIsOnSystemFramework(system_location_path.c_str()));
+
+ ScopedObjectAccess soa(Thread::Current());
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ std::string error_msg;
+ ObjPtr<mirror::ClassLoader> class_loader;
+
+ ASSERT_TRUE(Copy(GetTestDexFileName("Main"), system_location_path, &error_msg)) << error_msg;
+ ASSERT_TRUE(LoadDexFiles(system_location_path, soa, &dex_files, &class_loader, &error_msg))
+ << error_msg;
+ ASSERT_GE(dex_files.size(), 1u);
+ ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kApplication));
+
+ dex_files.clear();
+ ASSERT_EQ(0, remove(system_location_path.c_str()));
+}
+
+TEST_F(HiddenApiTest, DexDomain_SystemFrameworkDir) {
+ // Load file from a system/framework directory and check that it is flagged as a framework dex.
+ std::string system_framework_location_path = GetAndroidRoot() + "/framework/foo.jar";
+ ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_location_path.c_str()));
+
+ ScopedObjectAccess soa(Thread::Current());
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ std::string error_msg;
+ ObjPtr<mirror::ClassLoader> class_loader;
+
+ ASSERT_TRUE(Copy(GetTestDexFileName("Main"), system_framework_location_path, &error_msg))
+ << error_msg;
+ ASSERT_TRUE(LoadDexFiles(system_framework_location_path,
+ soa,
+ &dex_files,
+ &class_loader,
+ &error_msg)) << error_msg;
+ ASSERT_GE(dex_files.size(), 1u);
+ ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kPlatform));
+
+ dex_files.clear();
+ ASSERT_EQ(0, remove(system_framework_location_path.c_str()));
+}
+
+TEST_F(HiddenApiTest, DexDomain_DataDir_MultiDex) {
+ // Load multidex file from a non-system directory and check that it is not flagged as framework.
+ std::string data_multi_location_path = android_data_ + "/multifoo.jar";
+ ASSERT_FALSE(LocationIsOnSystemFramework(data_multi_location_path.c_str()));
+
+ ScopedObjectAccess soa(Thread::Current());
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ std::string error_msg;
+ ObjPtr<mirror::ClassLoader> class_loader;
+
+ ASSERT_TRUE(Copy(GetTestDexFileName("MultiDex"), data_multi_location_path, &error_msg))
+ << error_msg;
+ ASSERT_TRUE(LoadDexFiles(data_multi_location_path, soa, &dex_files, &class_loader, &error_msg))
+ << error_msg;
+ ASSERT_GE(dex_files.size(), 1u);
+ ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kApplication));
+
+ dex_files.clear();
+ ASSERT_EQ(0, remove(data_multi_location_path.c_str()));
+}
+
+TEST_F(HiddenApiTest, DexDomain_SystemDir_MultiDex) {
+ // Load multidex file from a system, non-framework directory and check that it is not flagged
+ // as framework.
+ std::string system_multi_location_path = GetAndroidRoot() + "/multifoo.jar";
+ ASSERT_FALSE(LocationIsOnSystemFramework(system_multi_location_path.c_str()));
+
+ ScopedObjectAccess soa(Thread::Current());
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ std::string error_msg;
+ ObjPtr<mirror::ClassLoader> class_loader;
+
+ ASSERT_TRUE(Copy(GetTestDexFileName("MultiDex"), system_multi_location_path, &error_msg))
+ << error_msg;
+ ASSERT_TRUE(LoadDexFiles(system_multi_location_path, soa, &dex_files, &class_loader, &error_msg))
+ << error_msg;
+ ASSERT_GT(dex_files.size(), 1u);
+ ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kApplication));
+
+ dex_files.clear();
+ ASSERT_EQ(0, remove(system_multi_location_path.c_str()));
+}
+
+TEST_F(HiddenApiTest, DexDomain_SystemFrameworkDir_MultiDex) {
+ // Load multidex file from a system/framework directory and check that it is flagged as a
+ // framework dex.
+ std::string system_framework_multi_location_path = GetAndroidRoot() + "/framework/multifoo.jar";
+ ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_multi_location_path.c_str()));
+
+ ScopedObjectAccess soa(Thread::Current());
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ std::string error_msg;
+ ObjPtr<mirror::ClassLoader> class_loader;
+
+ ASSERT_TRUE(Copy(GetTestDexFileName("MultiDex"),
+ system_framework_multi_location_path,
+ &error_msg)) << error_msg;
+ ASSERT_TRUE(LoadDexFiles(system_framework_multi_location_path,
+ soa,
+ &dex_files,
+ &class_loader,
+ &error_msg)) << error_msg;
+ ASSERT_GT(dex_files.size(), 1u);
+ ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kPlatform));
+
+ dex_files.clear();
+ ASSERT_EQ(0, remove(system_framework_multi_location_path.c_str()));
+}
+
} // namespace art