1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_PROXY_TEST_H_
18 #define ART_RUNTIME_PROXY_TEST_H_
19 
20 #include <jni.h>
21 #include <vector>
22 
23 #include "art_method-inl.h"
24 #include "class_linker-inl.h"
25 #include "class_root-inl.h"
26 #include "mirror/class-inl.h"
27 #include "mirror/method.h"
28 #include "obj_ptr-inl.h"
29 
30 namespace art {
31 namespace proxy_test {
32 
33 // Generate a proxy class with the given name and interfaces. This is a simplification from what
34 // libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and
35 // we do not declare exceptions.
GenerateProxyClass(ScopedObjectAccess & soa,jobject jclass_loader,ClassLinker * class_linker,const char * className,const std::vector<Handle<mirror::Class>> & interfaces)36 inline ObjPtr<mirror::Class> GenerateProxyClass(ScopedObjectAccess& soa,
37                                                 jobject jclass_loader,
38                                                 ClassLinker* class_linker,
39                                                 const char* className,
40                                                 const std::vector<Handle<mirror::Class>>& interfaces)
41     REQUIRES_SHARED(Locks::mutator_lock_) {
42   StackHandleScope<1> hs(soa.Self());
43   Handle<mirror::Class> javaLangObject = hs.NewHandle(GetClassRoot<mirror::Object>());
44   CHECK(javaLangObject != nullptr);
45 
46   jclass javaLangClass = soa.AddLocalReference<jclass>(GetClassRoot<mirror::Class>());
47 
48   // Builds the interfaces array.
49   jobjectArray proxyClassInterfaces =
50       soa.Env()->NewObjectArray(interfaces.size(), javaLangClass, /* initialElement= */ nullptr);
51   soa.Self()->AssertNoPendingException();
52   for (size_t i = 0; i < interfaces.size(); ++i) {
53     soa.Env()->SetObjectArrayElement(proxyClassInterfaces, i,
54                                      soa.AddLocalReference<jclass>(interfaces[i].Get()));
55   }
56 
57   // Builds the method array.
58   jsize methods_count = 3;  // Object.equals, Object.hashCode and Object.toString.
59   for (Handle<mirror::Class> interface : interfaces) {
60     methods_count += interface->NumVirtualMethods();
61   }
62   jobjectArray proxyClassMethods = soa.Env()->NewObjectArray(
63       methods_count,
64       soa.AddLocalReference<jclass>(GetClassRoot<mirror::Method>()),
65       /* initialElement= */ nullptr);
66   soa.Self()->AssertNoPendingException();
67 
68   jsize array_index = 0;
69   // Fill the method array
70   DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
71   ArtMethod* method = javaLangObject->FindClassMethod(
72       "equals", "(Ljava/lang/Object;)Z", kRuntimePointerSize);
73   CHECK(method != nullptr);
74   CHECK(!method->IsDirect());
75   CHECK(method->GetDeclaringClass() == javaLangObject.Get());
76   DCHECK(!Runtime::Current()->IsActiveTransaction());
77   soa.Env()->SetObjectArrayElement(
78       proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
79           mirror::Method::CreateFromArtMethod<kRuntimePointerSize>(soa.Self(), method)));
80   method = javaLangObject->FindClassMethod("hashCode", "()I", kRuntimePointerSize);
81   CHECK(method != nullptr);
82   CHECK(!method->IsDirect());
83   CHECK(method->GetDeclaringClass() == javaLangObject.Get());
84   soa.Env()->SetObjectArrayElement(
85       proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
86           mirror::Method::CreateFromArtMethod<kRuntimePointerSize>(soa.Self(), method)));
87   method = javaLangObject->FindClassMethod(
88       "toString", "()Ljava/lang/String;", kRuntimePointerSize);
89   CHECK(method != nullptr);
90   CHECK(!method->IsDirect());
91   CHECK(method->GetDeclaringClass() == javaLangObject.Get());
92   soa.Env()->SetObjectArrayElement(
93       proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
94           mirror::Method::CreateFromArtMethod<kRuntimePointerSize>(soa.Self(), method)));
95   // Now adds all interfaces virtual methods.
96   for (Handle<mirror::Class> interface : interfaces) {
97     for (auto& m : interface->GetDeclaredVirtualMethods(kRuntimePointerSize)) {
98       soa.Env()->SetObjectArrayElement(
99           proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
100               mirror::Method::CreateFromArtMethod<kRuntimePointerSize>(soa.Self(), &m)));
101     }
102   }
103   CHECK_EQ(array_index, methods_count);
104 
105   // Builds an empty exception array.
106   jobjectArray proxyClassThrows = soa.Env()->NewObjectArray(0, javaLangClass, nullptr);
107   soa.Self()->AssertNoPendingException();
108 
109   ObjPtr<mirror::Class> proxyClass = class_linker->CreateProxyClass(
110       soa,
111       soa.Env()->NewStringUTF(className),
112       proxyClassInterfaces,
113       jclass_loader,
114       proxyClassMethods,
115       proxyClassThrows);
116   soa.Self()->AssertNoPendingException();
117   return proxyClass;
118 }
119 
120 }  // namespace proxy_test
121 }  // namespace art
122 
123 #endif  // ART_RUNTIME_PROXY_TEST_H_
124