安卓10
类图
双亲委派机制
Java层
BaseDexClassLoader 没有loadClass实现,继承的是 ClassLoader 实现
路径 libcore\ojluni\src\main\java\java\lang\ClassLoader.java
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
return c;
}
libcore\dalvik\src\main\java\dalvik\system\BaseDexClassLoader.java
调用自身findClass
protected Class<?> findClass(String name) throws ClassNotFoundException {
// First, check whether the class is present in our shared libraries.
if (sharedLibraryLoaders != null) {
for (ClassLoader loader : sharedLibraryLoaders) {
try {
return loader.loadClass(name);
} catch (ClassNotFoundException ignored) {
}
}
}
// Check whether the class in question is present in the dexPath that
// this classloader operates on.
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException(
"Didn't find class \"" + name + "\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
libcore\dalvik\src\main\java\dalvik\system\DexPathList.java
/**
* Finds the named class in one of the dex files pointed at by
* this instance. This will find the one in the earliest listed
* path element. If the class is found but has not yet been
* defined, then this method will define it in the defining
* context that this instance was constructed with.
*
* @param name of class to find
* @param suppressed exceptions encountered whilst finding the class
* @return the named class or {@code null} if the class is not
* found in any of the dex files
*/
public Class<?> findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
if (dexElementsSuppressedExceptions != null) {
suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
}
return null;
}
//静态内部类 element 的findClass
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
libcore\dalvik\src\main\java\dalvik\system\DexFile.java
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) {
return defineClass(name, loader, mCookie, this, suppressed);
}
private static Class defineClass(String name, ClassLoader loader, Object cookie,
DexFile dexFile, List<Throwable> suppressed) {
Class result = null;
try {
result = defineClassNative(name, loader, cookie, dexFile);
} catch (NoClassDefFoundError e) {
if (suppressed != null) {
suppressed.add(e);
}
} catch (ClassNotFoundException e) {
if (suppressed != null) {
suppressed.add(e);
}
}
return result;
}
private static native Class defineClassNative(String name, ClassLoader loader, Object cookie,
DexFile dexFile)
throws ClassNotFoundException, NoClassDefFoundError;
native层
art\runtime\native\dalvik_system_DexFile.cc
ClassLinker::DefineClass
—>ClassLinker::LoadClass 脱壳点
static jclass DexFile_defineClassNative(JNIEnv* env,
jclass,
jstring javaName,
jobject javaLoader,
jobject cookie,
jobject dexFile) {
const std::string descriptor(DotToDescriptor(class_name.c_str()));
const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str()));
for (auto& dex_file : dex_files) {
const dex::ClassDef* dex_class_def =
OatDexFile::FindClassDef(*dex_file, descriptor.c_str(), hash);
if (dex_class_def != nullptr) {
ScopedObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
ObjPtr<mirror::DexCache> dex_cache =
class_linker->RegisterDexFile(*dex_file, class_loader.Get());
ObjPtr<mirror::Class> result = class_linker->DefineClass(soa.Self(),
descriptor.c_str(),
hash,
class_loader,
*dex_file,
*dex_class_def);
// Add the used dex file. This only required for the DexFile.loadClass API since normal
// class loaders already keep their dex files live.
class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile),
class_loader.Get());
if (result != nullptr) {
VLOG(class_linker) << "DexFile_defineClassNative returning " << result
<< " for " << class_name.c_str();
return soa.AddLocalReference<jclass>(result);
}
}
}
VLOG(class_linker) << "Failed to find dex_class_def " << class_name.c_str();
return nullptr;
}
art/runtime/class_linker.cc
DefineClass 可以重点看
ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const dex::ClassDef& dex_class_def) {
SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get());
// Add the newly loaded class to the loaded classes table.
ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);
// Load the fields and other things after we are inserted in the table. This is so that we don't
// end up allocating unfree-able linear alloc resources and then lose the race condition. The
// other reason is that the field roots are only visited from the class table. So we need to be
// inserted before we allocate / fill in these fields.
LoadClass(self, *new_dex_file, *new_class_def, klass);
if (self->IsExceptionPending()) {
VLOG(class_linker) << self->GetException()->Dump();
// An exception occured during load, set status to erroneous while holding klass' lock in case
// notification is necessary.
if (!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return nullptr;
}
// Finish loading (if necessary) by finding parents
CHECK(!klass->IsLoaded());
if (!LoadSuperAndInterfaces(klass, *new_dex_file)) {
// Loading failed.
if (!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return nullptr;
}
CHECK(klass->IsLoaded());
// At this point the class is loaded. Publish a ClassLoad event.
// Note: this may be a temporary class. It is a listener's responsibility to handle this.
Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(klass);
// Link the class (if necessary)
CHECK(!klass->IsResolved());
// TODO: Use fast jobjects?
auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
MutableHandle<mirror::Class> h_new_class = hs.NewHandle<mirror::Class>(nullptr);
if (!LinkClass(self, descriptor, klass, interfaces, &h_new_class)) {
// Linking failed.
if (!klass->IsErroneous()) {
mirror::Class::SetStatus(klass, ClassStatus::kErrorUnresolved, self);
}
return nullptr;
}
/*
* We send CLASS_PREPARE events to the debugger from here. The
* definition of "preparation" is creating the static fields for a
* class and initializing them to the standard default values, but not
* executing any code (that comes later, during "initialization").
*
* We did the static preparation in LinkClass.
*
* The class has been prepared and resolved but possibly not yet verified
* at this point.
*/
Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(klass, h_new_class);
// Notify native debugger of the new class and its layout.
jit::Jit::NewTypeLoadedIfUsingJit(h_new_class.Get());
return h_new_class.Get();
}
void ClassLinker::LoadClass(Thread* self,
const DexFile& dex_file,
const dex::ClassDef& dex_class_def,
Handle<mirror::Class> klass) {
ClassAccessor accessor(dex_file,
dex_class_def,
/* parse_hiddenapi_class_data= */ klass->IsBootStrapClassLoaded());
if (!accessor.HasClassData()) {
return;
}
Runtime* const runtime = Runtime::Current();
{
// Note: We cannot have thread suspension until the field and method arrays are setup or else
// Class::VisitFieldRoots may miss some fields or methods.
ScopedAssertNoThreadSuspension nts(__FUNCTION__);
// Load static fields.
// We allow duplicate definitions of the same field in a class_data_item
// but ignore the repeated indexes here, b/21868015.
LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self,
allocator,
accessor.NumStaticFields());
LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,
allocator,
accessor.NumInstanceFields());
size_t num_sfields = 0u;
size_t num_ifields = 0u;
uint32_t last_static_field_idx = 0u;
uint32_t last_instance_field_idx = 0u;
// Methods
bool has_oat_class = false;
const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler())
? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class)
: OatFile::OatClass::Invalid();
const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;
klass->SetMethodsPtr(
AllocArtMethodArray(self, allocator, accessor.NumMethods()),
accessor.NumDirectMethods(),
accessor.NumVirtualMethods());
size_t class_def_method_index = 0;
uint32_t last_dex_method_index = dex::kDexNoIndex;
size_t last_class_def_method_index = 0;
// Use the visitor since the ranged based loops are bit slower from seeking. Seeking to the
// methods needs to decode all of the fields.
accessor.VisitFieldsAndMethods([&](
const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t field_idx = field.GetIndex();
DCHECK_GE(field_idx, last_static_field_idx); // Ordering enforced by DexFileVerifier.
if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) {
LoadField(field, klass, &sfields->At(num_sfields));
++num_sfields;
last_static_field_idx = field_idx;
}
}, [&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t field_idx = field.GetIndex();
DCHECK_GE(field_idx, last_instance_field_idx); // Ordering enforced by DexFileVerifier.
if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) {
LoadField(field, klass, &ifields->At(num_ifields));
++num_ifields;
last_instance_field_idx = field_idx;
}
}, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {
ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index,
image_pointer_size_);
LoadMethod(dex_file, method, klass, art_method);
LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
uint32_t it_method_index = method.GetIndex();
if (last_dex_method_index == it_method_index) {
// duplicate case
art_method->SetMethodIndex(last_class_def_method_index);
} else {
art_method->SetMethodIndex(class_def_method_index);
last_dex_method_index = it_method_index;
last_class_def_method_index = class_def_method_index;
}
++class_def_method_index;
}, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {
ArtMethod* art_method = klass->GetVirtualMethodUnchecked(
class_def_method_index - accessor.NumDirectMethods(),
image_pointer_size_);
LoadMethod(dex_file, method, klass, art_method);
LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
++class_def_method_index;
});
if (UNLIKELY(num_ifields + num_sfields != accessor.NumFields())) {
LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor()
<< " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields()
<< ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields()
<< ")";
// NOTE: Not shrinking the over-allocated sfields/ifields, just setting size.
if (sfields != nullptr) {
sfields->SetSize(num_sfields);
}
if (ifields != nullptr) {
ifields->SetSize(num_ifields);
}
}
// Set the field arrays.
klass->SetSFieldsPtr(sfields);
DCHECK_EQ(klass->NumStaticFields(), num_sfields);
klass->SetIFieldsPtr(ifields);
DCHECK_EQ(klass->NumInstanceFields(), num_ifields);
}
// Ensure that the card is marked so that remembered sets pick up native roots.
WriteBarrier::ForEveryFieldWrite(klass.Get());
self->AllowThreadSuspension();
}
参考
Android类加载流程分析