/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_RUNTIME_PROXY_TEST_H_ #define ART_RUNTIME_PROXY_TEST_H_ #include #include #include "art_method-inl.h" #include "class_linker-inl.h" #include "class_root.h" #include "mirror/class-inl.h" #include "mirror/method.h" #include "obj_ptr-inl.h" namespace art { namespace proxy_test { // Generate a proxy class with the given name and interfaces. This is a simplification from what // libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and // we do not declare exceptions. ObjPtr GenerateProxyClass(ScopedObjectAccess& soa, jobject jclass_loader, ClassLinker* class_linker, const char* className, const std::vector>& interfaces) REQUIRES_SHARED(Locks::mutator_lock_) { StackHandleScope<1> hs(soa.Self()); Handle javaLangObject = hs.NewHandle(GetClassRoot()); CHECK(javaLangObject != nullptr); jclass javaLangClass = soa.AddLocalReference(GetClassRoot()); // Builds the interfaces array. jobjectArray proxyClassInterfaces = soa.Env()->NewObjectArray(interfaces.size(), javaLangClass, /* initialElement= */ nullptr); soa.Self()->AssertNoPendingException(); for (size_t i = 0; i < interfaces.size(); ++i) { soa.Env()->SetObjectArrayElement(proxyClassInterfaces, i, soa.AddLocalReference(interfaces[i].Get())); } // Builds the method array. jsize methods_count = 3; // Object.equals, Object.hashCode and Object.toString. for (Handle interface : interfaces) { methods_count += interface->NumVirtualMethods(); } jobjectArray proxyClassMethods = soa.Env()->NewObjectArray( methods_count, soa.AddLocalReference(GetClassRoot()), /* initialElement= */ nullptr); soa.Self()->AssertNoPendingException(); jsize array_index = 0; // Fill the method array DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize); ArtMethod* method = javaLangObject->FindClassMethod( "equals", "(Ljava/lang/Object;)Z", kRuntimePointerSize); CHECK(method != nullptr); CHECK(!method->IsDirect()); CHECK(method->GetDeclaringClass() == javaLangObject.Get()); DCHECK(!Runtime::Current()->IsActiveTransaction()); soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference( mirror::Method::CreateFromArtMethod(soa.Self(), method))); method = javaLangObject->FindClassMethod("hashCode", "()I", kRuntimePointerSize); CHECK(method != nullptr); CHECK(!method->IsDirect()); CHECK(method->GetDeclaringClass() == javaLangObject.Get()); soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference( mirror::Method::CreateFromArtMethod(soa.Self(), method))); method = javaLangObject->FindClassMethod( "toString", "()Ljava/lang/String;", kRuntimePointerSize); CHECK(method != nullptr); CHECK(!method->IsDirect()); CHECK(method->GetDeclaringClass() == javaLangObject.Get()); soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference( mirror::Method::CreateFromArtMethod(soa.Self(), method))); // Now adds all interfaces virtual methods. for (Handle interface : interfaces) { for (auto& m : interface->GetDeclaredVirtualMethods(kRuntimePointerSize)) { soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference( mirror::Method::CreateFromArtMethod(soa.Self(), &m))); } } CHECK_EQ(array_index, methods_count); // Builds an empty exception array. jobjectArray proxyClassThrows = soa.Env()->NewObjectArray(0, javaLangClass, nullptr); soa.Self()->AssertNoPendingException(); ObjPtr proxyClass = class_linker->CreateProxyClass( soa, soa.Env()->NewStringUTF(className), proxyClassInterfaces, jclass_loader, proxyClassMethods, proxyClassThrows); soa.Self()->AssertNoPendingException(); return proxyClass; } } // namespace proxy_test } // namespace art #endif // ART_RUNTIME_PROXY_TEST_H_