/** parameter types of a proxy class constructor */
private static final Class<?>[] constructorParams = { InvocationHandler.class };
/**
\* a cache of proxy classes
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
final Class<?>[] intfs = interfaces.clone();
/*
\* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);//main
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
return cons.newInstance(new Object[]{h});
/**
\* Generate a proxy class. Must call the checkProxyAccess method
\* to perform permission checks before calling this.
*/
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
/**
\* A factory function that generates, defines and returns the proxy class given
\* the ClassLoader and array of interfaces.
*/
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
return generateProxy(proxyName, interfaces, loader, methodsArray, exceptionsArray);
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
ClassLoader loader, Method[] methods,
Class<?>[][] exceptions);
// END Android-changed: How proxies are generated.
art/runtime/native/java_lang_reflect_Proxy.cc
static JNINativeMethod gMethods[] = {
FAST_NATIVE_METHOD(Proxy, generateProxy, "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"),
};
static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
jobject loader, jobjectArray methods, jobjectArray throws) {
ScopedFastNativeObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
soa, name, interfaces, loader, methods, throws));
}
art/runtime/class_linker.cc
mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
jstring name,
jobjectArray interfaces,
jobject loader,
jobjectArray methods,
jobjectArray throws) {
Thread* self = soa.Self();
StackHandleScope<10> hs(self);
MutableHandle<mirror::Class> temp_klass(hs.NewHandle(
AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class))));
temp_klass->SetObjectSize(sizeof(mirror::Proxy));
// Set the class access flags incl. VerificationAttempted, so we do not try to set the flag on
// the methods.
temp_klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
temp_klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader));
DCHECK_EQ(temp_klass->GetPrimitiveType(), Primitive::kPrimNot);
temp_klass->SetName(soa.Decode<mirror::String>(name));
temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
// Object has an empty iftable, copy it for that reason.
temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
mirror::Class::SetStatus(temp_klass, ClassStatus::kIdx, self);
//insert into classtable
ObjPtr<mirror::Class> existing = InsertClass(descriptor.c_str(), temp_klass.Get(), hash);
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, num_fields);
temp_klass->SetSFieldsPtr(sfields);
// 1. Create a static field 'interfaces' that holds the _declared_ interfaces implemented by
// our proxy, so Class.getInterfaces doesn't return the flattened set.
ArtField& interfaces_sfield = sfields->At(0);
interfaces_sfield.SetDexFieldIndex(0);
interfaces_sfield.SetDeclaringClass(temp_klass.Get());
interfaces_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
// 2. Create a static field 'throws' that holds exceptions thrown by our methods.
ArtField& throws_sfield = sfields->At(1);
throws_sfield.SetDexFieldIndex(1);
throws_sfield.SetDeclaringClass(temp_klass.Get());
throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
// They have as many virtual methods as the array
auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>>(methods));
// Create the methods array.
LengthPrefixedArray<ArtMethod>* proxy_class_methods = AllocArtMethodArray(
self, allocator, num_direct_methods + num_virtual_methods);
// Create the single direct method.
CreateProxyConstructor(temp_klass, temp_klass->GetDirectMethodUnchecked(0, image_pointer_size_));
// Create virtual method using specified prototypes.
// TODO These should really use the iterators.
for (size_t i = 0; i < num_virtual_methods; ++i) {
auto* virtual_method = temp_klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
auto* prototype = h_methods->Get(i)->GetArtMethod();
CreateProxyMethod(temp_klass, prototype, virtual_method);
DCHECK(virtual_method->GetDeclaringClass() != nullptr);
DCHECK(prototype->GetDeclaringClass() != nullptr);
}
// The super class is java.lang.reflect.Proxy
temp_klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy));
// Now effectively in the loaded state.
mirror::Class::SetStatus(temp_klass, ClassStatus::kLoaded, self);
LinkClass(self, descriptor.c_str(), temp_klass, h_interfaces, &klass)
Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(temp_klass, klass);
SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(klass.Get());
// Lock on klass is released. Lock new class object.
ObjectLock<mirror::Class> initialization_lock(self, klass);
mirror::Class::SetStatus(klass, ClassStatus::kInitialized, self);
return klass.Get();
}
enum class ClassStatus : uint8_t {
kNotReady = 0, // Zero-initialized Class object starts in this state.
kRetired = 1, // Retired, should not be used. Use the newly cloned one instead.
kErrorResolved = 2,
kErrorUnresolved = 3,
kIdx = 4, // Loaded, DEX idx in super_class_type_idx_ and interfaces_type_idx_.
kLoaded = 5, // DEX idx values resolved.
kResolving = 6, // Just cloned from temporary class object.
kResolved = 7, // Part of linking.
kVerifying = 8, // In the process of being verified.
kRetryVerificationAtRuntime = 9, // Compile time verification failed, retry at runtime.
kVerifyingAtRuntime = 10, // Retrying verification at runtime.
kVerified = 11, // Logically part of linking; done pre-init.
kSuperclassValidated = 12, // Superclass validation part of init done.
kInitializing = 13, // Class init in progress.
kInitialized = 14, // Ready to go.
kLast = kInitialized
};