summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc214
1 files changed, 140 insertions, 74 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 67513f9ce6..639fa7ec92 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -798,6 +798,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
FindSystemClass(self, "Ljava/lang/StackTraceElement;"));
SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass,
FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
+ SetClassRoot(ClassRoot::kJavaLangClassLoaderArrayClass,
+ FindSystemClass(self, "[Ljava/lang/ClassLoader;"));
// Create conflict tables that depend on the class linker.
runtime->FixupConflictTables();
@@ -1543,26 +1545,6 @@ void AppImageLoadingHelper::HandleAppImageStrings(gc::space::ImageSpace* space)
}
}
-// Update the class loader. Should only be used on classes in the image space.
-class UpdateClassLoaderVisitor {
- public:
- UpdateClassLoaderVisitor(gc::space::ImageSpace* space, ObjPtr<mirror::ClassLoader> class_loader)
- : space_(space),
- class_loader_(class_loader) {}
-
- bool operator()(ObjPtr<mirror::Class> klass) const REQUIRES_SHARED(Locks::mutator_lock_) {
- // Do not update class loader for boot image classes where the app image
- // class loader is only the initiating loader but not the defining loader.
- if (klass->GetClassLoader() != nullptr) {
- klass->SetClassLoader(class_loader_);
- }
- return true;
- }
-
- gc::space::ImageSpace* const space_;
- ObjPtr<mirror::ClassLoader> const class_loader_;
-};
-
static std::unique_ptr<const DexFile> OpenOatDexFile(const OatFile* oat_file,
const char* location,
std::string* error_msg)
@@ -2036,9 +2018,17 @@ bool ClassLinker::AddImageSpace(
ScopedTrace trace("AppImage:UpdateClassLoaders");
// Update class loader and resolved strings. If added_class_table is false, the resolved
// strings were forwarded UpdateAppImageClassLoadersAndDexCaches.
- UpdateClassLoaderVisitor visitor(space, class_loader.Get());
+ ObjPtr<mirror::ClassLoader> loader(class_loader.Get());
for (const ClassTable::TableSlot& root : temp_set) {
- visitor(root.Read());
+ // Note: We probably don't need the read barrier unless we copy the app image objects into
+ // the region space.
+ ObjPtr<mirror::Class> klass(root.Read());
+ // Do not update class loader for boot image classes where the app image
+ // class loader is only the initiating loader but not the defining loader.
+ // Avoid read barrier since we are comparing against null.
+ if (klass->GetClassLoader<kDefaultVerifyFlags, kWithoutReadBarrier>() != nullptr) {
+ klass->SetClassLoader</*kCheckTransaction=*/ false>(loader);
+ }
}
}
@@ -2527,6 +2517,35 @@ ClassPathEntry FindInClassPath(const char* descriptor,
return ClassPathEntry(nullptr, nullptr);
}
+bool ClassLinker::FindClassInSharedLibraries(ScopedObjectAccessAlreadyRunnable& soa,
+ Thread* self,
+ const char* descriptor,
+ size_t hash,
+ Handle<mirror::ClassLoader> class_loader,
+ /*out*/ ObjPtr<mirror::Class>* result) {
+ ArtField* field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader.Get());
+ if (raw_shared_libraries == nullptr) {
+ return true;
+ }
+
+ StackHandleScope<2> hs(self);
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries(
+ hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>()));
+ MutableHandle<mirror::ClassLoader> temp_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+ for (int32_t i = 0; i < shared_libraries->GetLength(); ++i) {
+ temp_loader.Assign(shared_libraries->Get(i));
+ if (!FindClassInBaseDexClassLoader(soa, self, descriptor, hash, temp_loader, result)) {
+ return false; // One of the shared libraries is not supported.
+ }
+ if (*result != nullptr) {
+ return true; // Found the class up the chain.
+ }
+ }
+ return true;
+}
+
bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
Thread* self,
const char* descriptor,
@@ -2542,6 +2561,7 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
if (IsPathOrDexClassLoader(soa, class_loader)) {
// For regular path or dex class loader the search order is:
// - parent
+ // - shared libraries
// - class loader dex files
// Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
@@ -2554,6 +2574,13 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
return true; // Found the class up the chain.
}
+ if (!FindClassInSharedLibraries(soa, self, descriptor, hash, class_loader, result)) {
+ return false; // One of the shared library loader is not supported.
+ }
+ if (*result != nullptr) {
+ return true; // Found the class in a shared library.
+ }
+
// Search the current class loader classpath.
*result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader);
return true;
@@ -2562,6 +2589,7 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
if (IsDelegateLastClassLoader(soa, class_loader)) {
// For delegate last, the search order is:
// - boot class path
+ // - shared libraries
// - class loader dex files
// - parent
*result = FindClassInBootClassLoaderClassPath(self, descriptor, hash);
@@ -2569,6 +2597,13 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
return true; // The class is part of the boot class path.
}
+ if (!FindClassInSharedLibraries(soa, self, descriptor, hash, class_loader, result)) {
+ return false; // One of the shared library loader is not supported.
+ }
+ if (*result != nullptr) {
+ return true; // Found the class in a shared library.
+ }
+
*result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader);
if (*result != nullptr) {
return true; // Found the class in the current class loader
@@ -3112,7 +3147,7 @@ bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void*
return (jit == nullptr) || !jit->GetCodeCache()->ContainsPc(quick_code);
}
- if (runtime->IsNativeDebuggable()) {
+ if (runtime->IsNativeDebuggableZygoteOK()) {
DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse());
// If we are doing native debugging, ignore application's AOT code,
// since we want to JIT it (at first use) with extra stackmaps for native
@@ -3435,14 +3470,8 @@ void ClassLinker::LoadField(const ClassAccessor::Field& field,
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
- // Get access flags from the DexFile. If this is a boot class path class,
- // also set its runtime hidden API access flags.
- uint32_t access_flags = field.GetAccessFlags();
- if (klass->IsBootStrapClassLoaded()) {
- access_flags = hiddenapi::EncodeForRuntime(
- access_flags, static_cast<hiddenapi::ApiList>(field.GetHiddenapiFlags()));
- }
- dst->SetAccessFlags(access_flags);
+ // Get access flags from the DexFile and set hiddenapi runtime access flags.
+ dst->SetAccessFlags(field.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(field));
}
void ClassLinker::LoadMethod(const DexFile& dex_file,
@@ -3458,13 +3487,8 @@ void ClassLinker::LoadMethod(const DexFile& dex_file,
dst->SetDeclaringClass(klass.Get());
dst->SetCodeItemOffset(method.GetCodeItemOffset());
- // Get access flags from the DexFile. If this is a boot class path class,
- // also set its runtime hidden API access flags.
- uint32_t access_flags = method.GetAccessFlags();
- if (klass->IsBootStrapClassLoaded()) {
- access_flags = hiddenapi::EncodeForRuntime(
- access_flags, static_cast<hiddenapi::ApiList>(method.GetHiddenapiFlags()));
- }
+ // Get access flags from the DexFile and set hiddenapi runtime access flags.
+ uint32_t access_flags = method.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(method);
if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
// Set finalizable flag on declaring class.
@@ -5070,8 +5094,10 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
ArtField* resolved_field = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
if (resolved_field == nullptr) {
// Populating cache of a dex file which defines `klass` should always be allowed.
- DCHECK_EQ(hiddenapi::GetMemberAction(
- field, class_loader.Get(), dex_cache.Get(), hiddenapi::kNone), hiddenapi::kAllow);
+ DCHECK(!hiddenapi::ShouldDenyAccessToMember(
+ field,
+ hiddenapi::AccessContext(class_loader.Get(), dex_cache.Get()),
+ hiddenapi::AccessMethod::kNone));
dex_cache->SetResolvedField(field_idx, field, image_pointer_size_);
} else {
DCHECK_EQ(field, resolved_field);
@@ -8102,8 +8128,9 @@ ArtMethod* ClassLinker::FindResolvedMethod(ObjPtr<mirror::Class> klass,
}
DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
if (resolved != nullptr &&
- hiddenapi::GetMemberAction(
- resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) {
+ hiddenapi::ShouldDenyAccessToMember(resolved,
+ hiddenapi::AccessContext(class_loader, dex_cache),
+ hiddenapi::AccessMethod::kLinking)) {
resolved = nullptr;
}
if (resolved != nullptr) {
@@ -8133,11 +8160,9 @@ static bool CheckNoSuchMethod(ArtMethod* method,
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_) {
return method == nullptr ||
- hiddenapi::GetMemberAction(method,
- class_loader,
- dex_cache,
- hiddenapi::kNone) // do not print warnings
- == hiddenapi::kDeny;
+ hiddenapi::ShouldDenyAccessToMember(method,
+ hiddenapi::AccessContext(class_loader, dex_cache),
+ hiddenapi::AccessMethod::kNone); // no warnings
}
ArtMethod* ClassLinker::FindIncompatibleMethod(ObjPtr<mirror::Class> klass,
@@ -8273,8 +8298,10 @@ ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(uint32_t method_idx,
resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, image_pointer_size_);
}
if (resolved != nullptr &&
- hiddenapi::GetMemberAction(
- resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking) == hiddenapi::kDeny) {
+ hiddenapi::ShouldDenyAccessToMember(
+ resolved,
+ hiddenapi::AccessContext(class_loader.Get(), dex_cache.Get()),
+ hiddenapi::AccessMethod::kLinking)) {
resolved = nullptr;
}
return resolved;
@@ -8373,8 +8400,9 @@ ArtField* ClassLinker::FindResolvedField(ObjPtr<mirror::Class> klass,
}
if (resolved != nullptr &&
- hiddenapi::GetMemberAction(
- resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) {
+ hiddenapi::ShouldDenyAccessToMember(resolved,
+ hiddenapi::AccessContext(class_loader, dex_cache),
+ hiddenapi::AccessMethod::kLinking)) {
resolved = nullptr;
}
@@ -8399,8 +8427,9 @@ ArtField* ClassLinker::FindResolvedFieldJLS(ObjPtr<mirror::Class> klass,
resolved = mirror::Class::FindField(self, klass, name, type);
if (resolved != nullptr &&
- hiddenapi::GetMemberAction(
- resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) {
+ hiddenapi::ShouldDenyAccessToMember(resolved,
+ hiddenapi::AccessContext(class_loader, dex_cache),
+ hiddenapi::AccessMethod::kLinking)) {
resolved = nullptr;
}
@@ -8967,21 +8996,14 @@ void ClassLinker::AllocAndSetPrimitiveArrayClassRoot(Thread* self,
CheckSystemClass(self, primitive_array_class, descriptor);
}
-jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
- const std::vector<const DexFile*>& dex_files,
- jclass loader_class,
- jobject parent_loader) {
- CHECK(self->GetJniEnv()->IsSameObject(loader_class,
- WellKnownClasses::dalvik_system_PathClassLoader) ||
- self->GetJniEnv()->IsSameObject(loader_class,
- WellKnownClasses::dalvik_system_DelegateLastClassLoader));
-
- // SOAAlreadyRunnable is protected, and we need something to add a global reference.
- // We could move the jobject to the callers, but all call-sites do this...
- ScopedObjectAccessUnchecked soa(self);
+ObjPtr<mirror::ClassLoader> ClassLinker::CreateWellKnownClassLoader(
+ Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ Handle<mirror::Class> loader_class,
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries,
+ Handle<mirror::ClassLoader> parent_loader) {
- // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
- StackHandleScope<6> hs(self);
+ StackHandleScope<5> hs(self);
ArtField* dex_elements_field =
jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements);
@@ -9071,8 +9093,8 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
}
// Create the class loader..
- Handle<mirror::Class> h_loader_class = hs.NewHandle(soa.Decode<mirror::Class>(loader_class));
- Handle<mirror::Object> h_class_loader = hs.NewHandle(h_loader_class->AllocObject(self));
+ Handle<mirror::ClassLoader> h_class_loader = hs.NewHandle<mirror::ClassLoader>(
+ ObjPtr<mirror::ClassLoader>::DownCast(loader_class->AllocObject(self)));
DCHECK(h_class_loader != nullptr);
// Set DexPathList.
ArtField* path_list_field =
@@ -9088,15 +9110,59 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
"parent",
"Ljava/lang/ClassLoader;");
DCHECK(parent_field != nullptr);
+ if (parent_loader.Get() == nullptr) {
+ ScopedObjectAccessUnchecked soa(self);
+ ObjPtr<mirror::Object> boot_loader(soa.Decode<mirror::Class>(
+ WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self));
+ parent_field->SetObject<false>(h_class_loader.Get(), boot_loader);
+ } else {
+ parent_field->SetObject<false>(h_class_loader.Get(), parent_loader.Get());
+ }
+
+ ArtField* shared_libraries_field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ DCHECK(shared_libraries_field != nullptr);
+ shared_libraries_field->SetObject<false>(h_class_loader.Get(), shared_libraries.Get());
+
+ return h_class_loader.Get();
+}
- ObjPtr<mirror::Object> parent = (parent_loader != nullptr)
- ? soa.Decode<mirror::ClassLoader>(parent_loader)
- : soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
- parent_field->SetObject<false>(h_class_loader.Get(), parent);
+jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ jclass loader_class,
+ jobject parent_loader) {
+ CHECK(self->GetJniEnv()->IsSameObject(loader_class,
+ WellKnownClasses::dalvik_system_PathClassLoader) ||
+ self->GetJniEnv()->IsSameObject(loader_class,
+ WellKnownClasses::dalvik_system_DelegateLastClassLoader));
+
+ // SOAAlreadyRunnable is protected, and we need something to add a global reference.
+ // We could move the jobject to the callers, but all call-sites do this...
+ ScopedObjectAccessUnchecked soa(self);
+
+ // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
+ StackHandleScope<3> hs(self);
+
+ Handle<mirror::Class> h_loader_class =
+ hs.NewHandle<mirror::Class>(soa.Decode<mirror::Class>(loader_class));
+ Handle<mirror::ClassLoader> parent =
+ hs.NewHandle<mirror::ClassLoader>(ObjPtr<mirror::ClassLoader>::DownCast(
+ (parent_loader != nullptr)
+ ? soa.Decode<mirror::ClassLoader>(parent_loader)
+ : nullptr));
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries =
+ hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr);
+
+ ObjPtr<mirror::ClassLoader> loader = CreateWellKnownClassLoader(
+ self,
+ dex_files,
+ h_loader_class,
+ shared_libraries,
+ parent);
// Make it a global ref and return.
ScopedLocalRef<jobject> local_ref(
- soa.Env(), soa.Env()->AddLocalReference<jobject>(h_class_loader.Get()));
+ soa.Env(), soa.Env()->AddLocalReference<jobject>(loader));
return soa.Env()->NewGlobalRef(local_ref.get());
}