1 /*
2  * Copyright (C) 2017 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 import java.lang.reflect.Constructor;
18 import java.lang.reflect.Field;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.lang.reflect.Modifier;
22 import java.util.Arrays;
23 
24 public class Reflection {
canDiscoverWithGetDeclaredField(Class<?> klass, String name)25   public static boolean canDiscoverWithGetDeclaredField(Class<?> klass, String name) {
26     try {
27       klass.getDeclaredField(name);
28       return true;
29     } catch (NoSuchFieldException ex) {
30       return false;
31     }
32   }
33 
canDiscoverWithGetDeclaredFields(Class<?> klass, String name)34   public static boolean canDiscoverWithGetDeclaredFields(Class<?> klass, String name) {
35     for (Field f : klass.getDeclaredFields()) {
36       if (f.getName().equals(name)) {
37         return true;
38       }
39     }
40     return false;
41   }
42 
canDiscoverWithGetField(Class<?> klass, String name)43   public static boolean canDiscoverWithGetField(Class<?> klass, String name) {
44     try {
45       klass.getField(name);
46       return true;
47     } catch (NoSuchFieldException ex) {
48       return false;
49     }
50   }
51 
canDiscoverWithGetFields(Class<?> klass, String name)52   public static boolean canDiscoverWithGetFields(Class<?> klass, String name) {
53     for (Field f : klass.getFields()) {
54       if (f.getName().equals(name)) {
55         return true;
56       }
57     }
58     return false;
59   }
60 
canGetField(Class<?> klass, String name)61   public static boolean canGetField(Class<?> klass, String name) {
62     try {
63       Field f = klass.getDeclaredField(name);
64       f.setAccessible(true);
65       f.getInt(Modifier.isStatic(f.getModifiers()) ? null : klass.newInstance());
66       return true;
67     } catch (Exception ex) {
68       ex.printStackTrace();
69       return false;
70     }
71   }
72 
canSetField(Class<?> klass, String name)73   public static boolean canSetField(Class<?> klass, String name) {
74     try {
75       Field f = klass.getDeclaredField(name);
76       f.setAccessible(true);
77       f.setInt(Modifier.isStatic(f.getModifiers()) ? null : klass.newInstance(), 42);
78       return true;
79     } catch (Exception ex) {
80       ex.printStackTrace();
81       return false;
82     }
83   }
84 
canDiscoverWithGetDeclaredMethod(Class<?> klass, String name)85   public static boolean canDiscoverWithGetDeclaredMethod(Class<?> klass, String name) {
86     try {
87       klass.getDeclaredMethod(name);
88       return true;
89     } catch (NoSuchMethodException ex) {
90       return false;
91     }
92   }
93 
canDiscoverWithGetDeclaredMethods(Class<?> klass, String name)94   public static boolean canDiscoverWithGetDeclaredMethods(Class<?> klass, String name) {
95     for (Method m : klass.getDeclaredMethods()) {
96       if (m.getName().equals(name)) {
97         return true;
98       }
99     }
100     return false;
101   }
102 
canDiscoverWithGetMethod(Class<?> klass, String name)103   public static boolean canDiscoverWithGetMethod(Class<?> klass, String name) {
104     try {
105       klass.getMethod(name);
106       return true;
107     } catch (NoSuchMethodException ex) {
108       return false;
109     }
110   }
111 
canDiscoverWithGetMethods(Class<?> klass, String name)112   public static boolean canDiscoverWithGetMethods(Class<?> klass, String name) {
113     for (Method m : klass.getMethods()) {
114       if (m.getName().equals(name)) {
115         return true;
116       }
117     }
118     return false;
119   }
120 
canInvokeMethod(Class<?> klass, String name)121   public static boolean canInvokeMethod(Class<?> klass, String name) {
122     try {
123       Method m = klass.getDeclaredMethod(name);
124       m.setAccessible(true);
125       m.invoke(klass.isInterface() ? null : klass.newInstance());
126       return true;
127     } catch (Exception ex) {
128       ex.printStackTrace();
129       return false;
130     }
131   }
132 
canDiscoverWithGetDeclaredConstructor(Class<?> klass, Class<?> args[])133   public static boolean canDiscoverWithGetDeclaredConstructor(Class<?> klass, Class<?> args[]) {
134     try {
135       klass.getDeclaredConstructor(args);
136       return true;
137     } catch (NoSuchMethodException ex) {
138       return false;
139     }
140   }
141 
canDiscoverWithGetDeclaredConstructors(Class<?> klass, Class<?> args[])142   public static boolean canDiscoverWithGetDeclaredConstructors(Class<?> klass, Class<?> args[]) {
143     for (Constructor c : klass.getDeclaredConstructors()) {
144       if (Arrays.equals(c.getParameterTypes(), args)) {
145         return true;
146       }
147     }
148     return false;
149   }
150 
canDiscoverWithGetConstructor(Class<?> klass, Class<?> args[])151   public static boolean canDiscoverWithGetConstructor(Class<?> klass, Class<?> args[]) {
152     try {
153       klass.getConstructor(args);
154       return true;
155     } catch (NoSuchMethodException ex) {
156       return false;
157     }
158   }
159 
canDiscoverWithGetConstructors(Class<?> klass, Class<?> args[])160   public static boolean canDiscoverWithGetConstructors(Class<?> klass, Class<?> args[]) {
161     for (Constructor c : klass.getConstructors()) {
162       if (Arrays.equals(c.getParameterTypes(), args)) {
163         return true;
164       }
165     }
166     return false;
167   }
168 
canInvokeConstructor(Class<?> klass, Class<?> args[], Object[] initargs)169   public static boolean canInvokeConstructor(Class<?> klass, Class<?> args[], Object[] initargs) {
170     try {
171       Constructor c = klass.getDeclaredConstructor(args);
172       c.setAccessible(true);
173       c.newInstance(initargs);
174       return true;
175     } catch (Exception ex) {
176       ex.printStackTrace();
177       return false;
178     }
179   }
180 
canUseNewInstance(Class<?> klass)181   public static boolean canUseNewInstance(Class<?> klass) throws IllegalAccessException {
182     try {
183       klass.newInstance();
184       return true;
185     } catch (InstantiationException ex) {
186       return false;
187     }
188   }
189 
canDiscoverMethodWithMetaReflection(Class<?> klass, String name, boolean hardeningEnabled)190   public static boolean canDiscoverMethodWithMetaReflection(Class<?> klass, String name,
191       boolean hardeningEnabled) {
192     try {
193       setHiddenApiCheckHardening(hardeningEnabled);
194       Method metaGetDeclaredMethod =
195           Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
196       // Assumes method without parameters.
197       return ((Method)metaGetDeclaredMethod.invoke(klass, name,  null)) != null;
198     } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
199       return false;
200     }
201   }
202 
canDiscoverFieldWithMetaReflection(Class<?> klass, String name, boolean hardeningEnabled)203   public static boolean canDiscoverFieldWithMetaReflection(Class<?> klass, String name,
204       boolean hardeningEnabled) {
205     try {
206       setHiddenApiCheckHardening(hardeningEnabled);
207       Method metaGetDeclaredField =
208           Class.class.getDeclaredMethod("getDeclaredField", String.class);
209       return ((Field)metaGetDeclaredField.invoke(klass, name)) != null;
210     } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
211       return false;
212     }
213   }
214 
canDiscoverConstructorWithMetaReflection(Class<?> klass, Class<?> args[], boolean hardeningEnabled)215   public static boolean canDiscoverConstructorWithMetaReflection(Class<?> klass, Class<?> args[],
216       boolean hardeningEnabled) {
217     try {
218       setHiddenApiCheckHardening(hardeningEnabled);
219       Method metaGetDeclaredConstructor =
220           Class.class.getDeclaredMethod("getDeclaredConstructor", Class[].class);
221       return ((Constructor<?>)metaGetDeclaredConstructor.invoke(klass, (Object)args)) != null;
222     } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
223       return false;
224     }
225   }
226 
getHiddenApiAccessFlags()227   private static native int getHiddenApiAccessFlags();
setHiddenApiCheckHardening(boolean value)228   private static native void setHiddenApiCheckHardening(boolean value);
229 
canObserveFieldHiddenAccessFlags(Class<?> klass, String name)230   public static boolean canObserveFieldHiddenAccessFlags(Class<?> klass, String name)
231       throws Exception {
232     return (klass.getDeclaredField(name).getModifiers() & getHiddenApiAccessFlags()) != 0;
233   }
234 
canObserveMethodHiddenAccessFlags(Class<?> klass, String name)235   public static boolean canObserveMethodHiddenAccessFlags(Class<?> klass, String name)
236       throws Exception {
237     return (klass.getDeclaredMethod(name).getModifiers() & getHiddenApiAccessFlags()) != 0;
238   }
239 
canObserveConstructorHiddenAccessFlags(Class<?> klass, Class<?> args[])240   public static boolean canObserveConstructorHiddenAccessFlags(Class<?> klass, Class<?> args[])
241       throws Exception {
242     return (klass.getConstructor(args).getModifiers() & getHiddenApiAccessFlags()) != 0;
243   }
244 }
245