summaryrefslogtreecommitdiff
path: root/runtime/class_loader_context_test.cc
diff options
context:
space:
mode:
author Dan Zimmerman <danzimm@fb.com> 2019-12-23 06:59:06 -0800
committer Calin Juravle <calin@google.com> 2020-02-08 00:01:36 +0000
commitb682ea4d1f9f88ef41589007f385398033d61b65 (patch)
treeb843077f05e2fe37ce5f566dfc823552f289f562 /runtime/class_loader_context_test.cc
parent77aa6807053a830fe5c951c7cb700813d7e2e27b (diff)
Introduce BaseDexClassLoader.computeClassLoaderContextsNative
This will be used to compute the contexts that should be sent over to the dex load reporter. See associated changes in libcore & frameworks/base. Motivation: At the moment of committing there are two classloader context encoders- one in ART and one in the package manager. The duplicate logic is susceptible to divergences. For example at the moment if a package uses shared libraries and has secondary dex files then the context encoded for secondary dex files will be incorrect[1]. In order to eliminate this bug and future possible bugs lets centralize where all classloader context computation is done. [1]: The context will be incorrect because it doesn't take into account the shared libraries that are loaded at runtime. Test: m test-art-host-gtest-class_loader_context_test Test: m test-art-host-gtest Test: ./test/testrunner/testrunner.py --host -b Test: Introduced a set of tests for the new API(s) Test: See tests in associated libcore & framework/base commits Bug: 148494302 Change-Id: Id39293a2e1d3d05194f2864f4febb3e652bce075
Diffstat (limited to 'runtime/class_loader_context_test.cc')
-rw-r--r--runtime/class_loader_context_test.cc180
1 files changed, 180 insertions, 0 deletions
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 008327834b..e082c8cbcf 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -1136,6 +1136,186 @@ TEST_F(ClassLoaderContextTest, EncodeForDex2oatIMC) {
ASSERT_EQ(expected_encoding, context->EncodeContextForDex2oat(""));
}
+TEST_F(ClassLoaderContextTest, EncodeContextsSinglePath) {
+ jobject class_loader = LoadDexInPathClassLoader("Main", nullptr);
+ std::unique_ptr<ClassLoaderContext> context =
+ CreateContextForClassLoader(class_loader);
+
+ std::map<std::string, std::string> encodings = context->EncodeClassPathContexts("");
+ ASSERT_EQ(1u, encodings.size());
+ ASSERT_EQ("PCL[]", encodings.at(GetTestDexFileName("Main")));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsMultiDex) {
+ jobject class_loader = LoadDexInPathClassLoader("MultiDex", nullptr);
+ std::unique_ptr<ClassLoaderContext> context =
+ CreateContextForClassLoader(class_loader);
+
+ std::map<std::string, std::string> encodings = context->EncodeClassPathContexts("");
+ ASSERT_EQ(1u, encodings.size());
+ ASSERT_EQ("PCL[]", encodings.at(GetTestDexFileName("MultiDex")));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsRepeatedMultiDex) {
+ jobject top_class_loader = LoadDexInPathClassLoader("MultiDex", nullptr);
+ jobject middle_class_loader =
+ LoadDexInPathClassLoader("Main", top_class_loader);
+ jobject bottom_class_loader =
+ LoadDexInPathClassLoader("MultiDex", middle_class_loader);
+ std::unique_ptr<ClassLoaderContext> context =
+ CreateContextForClassLoader(bottom_class_loader);
+
+ std::map<std::string, std::string> encodings = context->EncodeClassPathContexts("");
+ ASSERT_EQ(1u, encodings.size());
+
+ std::string main_dex_name = GetTestDexFileName("Main");
+ std::string multidex_dex_name = GetTestDexFileName("MultiDex");
+ ASSERT_EQ(
+ "PCL[];PCL[" + main_dex_name + "];PCL[" + multidex_dex_name + "]",
+ encodings.at(multidex_dex_name));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsSinglePathWithShared) {
+ jobject class_loader_a = LoadDexInPathClassLoader("MyClass", nullptr);
+
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> libraries = hs.NewHandle(
+ mirror::ObjectArray<mirror::ClassLoader>::Alloc(
+ soa.Self(),
+ GetClassRoot<mirror::ObjectArray<mirror::ClassLoader>>(),
+ 1));
+ libraries->Set(0, soa.Decode<mirror::ClassLoader>(class_loader_a));
+
+ jobject class_loader_b = LoadDexInPathClassLoader(
+ "Main", nullptr, soa.AddLocalReference<jobject>(libraries.Get()));
+
+ std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader_b);
+
+ std::map<std::string, std::string> encodings = context->EncodeClassPathContexts("");
+ ASSERT_EQ(1u, encodings.size());
+ ASSERT_EQ(
+ "PCL[]{PCL[" + GetTestDexFileName("MyClass") + "]}",
+ encodings.at(GetTestDexFileName("Main")));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsMultiplePaths) {
+ jobject class_loader = LoadDexInPathClassLoader(
+ std::vector<std::string>{ "Main", "MultiDex"}, nullptr);
+
+ std::unique_ptr<ClassLoaderContext> context =
+ CreateContextForClassLoader(class_loader);
+
+ std::map<std::string, std::string> encodings = context->EncodeClassPathContexts("");
+ ASSERT_EQ(2u, encodings.size());
+ ASSERT_EQ("PCL[]", encodings.at(GetTestDexFileName("Main")));
+ ASSERT_EQ(
+ "PCL[" + GetTestDexFileName("Main") + "]", encodings.at(GetTestDexFileName("MultiDex")));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsMultiplePathsWithShared) {
+ jobject class_loader_a = LoadDexInPathClassLoader("MyClass", nullptr);
+
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<1> hs(soa.Self());
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> libraries = hs.NewHandle(
+ mirror::ObjectArray<mirror::ClassLoader>::Alloc(
+ soa.Self(),
+ GetClassRoot<mirror::ObjectArray<mirror::ClassLoader>>(),
+ 1));
+ libraries->Set(0, soa.Decode<mirror::ClassLoader>(class_loader_a));
+
+ jobject class_loader_b = LoadDexInPathClassLoader(
+ std::vector<std::string> { "Main", "MultiDex" },
+ nullptr, soa.AddLocalReference<jobject>(libraries.Get()));
+
+ std::unique_ptr<ClassLoaderContext> context =
+ CreateContextForClassLoader(class_loader_b);
+
+ std::map<std::string, std::string> encodings = context->EncodeClassPathContexts("");
+ ASSERT_EQ(2u, encodings.size());
+ const std::string context_suffix =
+ "{PCL[" + GetTestDexFileName("MyClass") + "]}";
+ ASSERT_EQ("PCL[]" + context_suffix, encodings.at(GetTestDexFileName("Main")));
+ ASSERT_EQ(
+ "PCL[" + GetTestDexFileName("Main") + "]" + context_suffix,
+ encodings.at(GetTestDexFileName("MultiDex")));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsIMC) {
+ jobject class_loader_a = LoadDexInPathClassLoader("Main", nullptr);
+ jobject class_loader_b =
+ LoadDexInInMemoryDexClassLoader("MyClass", class_loader_a);
+
+ std::unique_ptr<ClassLoaderContext> context =
+ CreateContextForClassLoader(class_loader_b);
+
+ std::map<std::string, std::string> encodings = context->EncodeClassPathContexts("");
+ ASSERT_EQ(1u, encodings.size());
+ ASSERT_EQ(
+ "IMC[];PCL[" + GetTestDexFileName("Main") + "]",
+ encodings.at("<unknown>"));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsForSingleDex) {
+ jobject class_loader = LoadDexInPathClassLoader("Main", nullptr);
+ std::map<std::string, std::string> encodings =
+ ClassLoaderContext::EncodeClassPathContextsForClassLoader(class_loader);
+ ASSERT_EQ(1u, encodings.size());
+ ASSERT_EQ("PCL[]", encodings.at(GetTestDexFileName("Main")));
+}
+
+static jobject CreateForeignClassLoader() {
+ ScopedObjectAccess soa(Thread::Current());
+ JNIEnv* env = soa.Env();
+
+ // We cannot instantiate a ClassLoader directly, so instead we allocate an Object to represent
+ // our foreign ClassLoader (this works because the runtime does proper instanceof checks before
+ // operating on this object.
+ jmethodID ctor = env->GetMethodID(WellKnownClasses::java_lang_Object, "<init>", "()V");
+ return env->NewObject(WellKnownClasses::java_lang_Object, ctor);
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsForUnsupportedBase) {
+ std::map<std::string, std::string> empty;
+ ASSERT_EQ(
+ empty, ClassLoaderContext::EncodeClassPathContextsForClassLoader(CreateForeignClassLoader()));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsForUnsupportedChain) {
+ jobject class_loader = LoadDexInPathClassLoader("Main", CreateForeignClassLoader());
+ std::map<std::string, std::string> encodings =
+ ClassLoaderContext::EncodeClassPathContextsForClassLoader(class_loader);
+ ASSERT_EQ(1u, encodings.size());
+ ASSERT_EQ(
+ ClassLoaderContext::kUnsupportedClassLoaderContextEncoding,
+ encodings.at(GetTestDexFileName("Main")));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsForUnsupportedChainMultiPath) {
+ jobject class_loader = LoadDexInPathClassLoader(std::vector<std::string> { "Main", "MyClass" },
+ CreateForeignClassLoader());
+ std::map<std::string, std::string> encodings =
+ ClassLoaderContext::EncodeClassPathContextsForClassLoader(class_loader);
+ ASSERT_EQ(2u, encodings.size());
+ ASSERT_EQ(
+ ClassLoaderContext::kUnsupportedClassLoaderContextEncoding,
+ encodings.at(GetTestDexFileName("Main")));
+ ASSERT_EQ(
+ ClassLoaderContext::kUnsupportedClassLoaderContextEncoding,
+ encodings.at(GetTestDexFileName("MyClass")));
+}
+
+TEST_F(ClassLoaderContextTest, EncodeContextsForUnsupportedChainMultiDex) {
+ jobject class_loader = LoadDexInPathClassLoader("MultiDex", CreateForeignClassLoader());
+ std::map<std::string, std::string> encodings =
+ ClassLoaderContext::EncodeClassPathContextsForClassLoader(class_loader);
+ ASSERT_EQ(1u, encodings.size());
+ ASSERT_EQ(
+ ClassLoaderContext::kUnsupportedClassLoaderContextEncoding,
+ encodings.at(GetTestDexFileName("MultiDex")));
+}
+
// TODO(calin) add a test which creates the context for a class loader together with dex_elements.
TEST_F(ClassLoaderContextTest, CreateContextForClassLoader) {
// The chain is