1 /*
2  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.internal.reflect;
27 
28 import java.lang.reflect.*;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.Map;
32 
33 import dalvik.system.VMStack;
34 
35 /** Common utility routines used by both java.lang and
36     java.lang.reflect */
37 
38 public class Reflection {
39 
40     // Android-removed: Dead code.
41     /*
42     /** Used to filter out fields and methods from certain classes from public
43         view, where they are sensitive or they may contain VM-internal objects.
44         These Maps are updated very rarely. Rather than synchronize on
45         each access, we use copy-on-write *
46     private static volatile Map<Class<?>,String[]> fieldFilterMap;
47     private static volatile Map<Class<?>,String[]> methodFilterMap;
48 
49     static {
50         Map<Class<?>,String[]> map = new HashMap<Class<?>,String[]>();
51         map.put(Reflection.class,
52             new String[] {"fieldFilterMap", "methodFilterMap"});
53         map.put(System.class, new String[] {"security"});
54         map.put(Class.class, new String[] {"classLoader"});
55         fieldFilterMap = map;
56 
57         methodFilterMap = new HashMap<>();
58     }
59    */
60 
61     // BEGIN Android-changed: getCallerClass() reimplementation.
62     // As of 2018-07 this implementation does not ignore frames
63     // associated with java.lang.reflect.Method.invoke() but this
64     // may change in future, see http://b/111800372 .
65     // Only code that expects or can handle the RI behavior (eg.
66     // code inherited from the RI) should call this method.
67     /*
68     /** Returns the class of the caller of the method calling this method,
69         ignoring frames associated with java.lang.reflect.Method.invoke()
70         and its implementation. *
71     @CallerSensitive
72     public static native Class<?> getCallerClass();
73     */
getCallerClass()74     public static Class<?> getCallerClass() {
75         // This method (getCallerClass()) constitutes another stack frame,
76         // so we need to call getStackClass2() rather than getStackClass1().
77         return VMStack.getStackClass2();
78     }
79     // END Android-changed: getCallerClass() reimplementation.
80 
81     // Android-removed: Dead code.
82     /*
83     /**
84      * @deprecated This method will be removed in JDK 9.
85      * This method is a private JDK API and retained temporarily for
86      * existing code to run until a replacement API is defined.
87      *
88     @Deprecated
89     public static native Class<?> getCallerClass(int depth);
90 
91     /** Retrieves the access flags written to the class file. For
92         inner classes these flags may differ from those returned by
93         Class.getModifiers(), which searches the InnerClasses
94         attribute to find the source-level access flags. This is used
95         instead of Class.getModifiers() for run-time access checks due
96         to compatibility reasons; see 4471811. Only the values of the
97         low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be
98         valid. *
99     public static native int getClassAccessFlags(Class<?> c);
100 
101     /** A quick "fast-path" check to try to avoid getCallerClass()
102         calls. *
103     public static boolean quickCheckMemberAccess(Class<?> memberClass,
104                                                  int modifiers)
105     {
106         return Modifier.isPublic(getClassAccessFlags(memberClass) & modifiers);
107     }
108     */
109 
ensureMemberAccess(Class<?> currentClass, Class<?> memberClass, Object target, int modifiers)110     public static void ensureMemberAccess(Class<?> currentClass,
111                                           Class<?> memberClass,
112                                           Object target,
113                                           int modifiers)
114         throws IllegalAccessException
115     {
116         if (currentClass == null || memberClass == null) {
117             throw new InternalError();
118         }
119 
120         if (!verifyMemberAccess(currentClass, memberClass, target, modifiers)) {
121             throw new IllegalAccessException("Class " + currentClass.getName() +
122                                              " can not access a member of class " +
123                                              memberClass.getName() +
124                                              " with modifiers \"" +
125                                              Modifier.toString(modifiers) +
126                                              "\"");
127         }
128     }
129 
verifyMemberAccess(Class<?> currentClass, Class<?> memberClass, Object target, int modifiers)130     public static boolean verifyMemberAccess(Class<?> currentClass,
131                                              // Declaring class of field
132                                              // or method
133                                              Class<?> memberClass,
134                                              // May be NULL in case of statics
135                                              Object   target,
136                                              int      modifiers)
137     {
138         // Verify that currentClass can access a field, method, or
139         // constructor of memberClass, where that member's access bits are
140         // "modifiers".
141 
142         boolean gotIsSameClassPackage = false;
143         boolean isSameClassPackage = false;
144 
145         if (currentClass == memberClass) {
146             // Always succeeds
147             return true;
148         }
149 
150         // Android-changed: verifyMemberAccess() consistent with class.getAccessFlags(T).
151         // The RI carries a separate getClassAccessFlags(Class) utility method
152         // with slightly different behavior for backwards compatibility. This
153         // does not apply on Android since the RI code was never adopted.
154         // if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
155         if (!Modifier.isPublic(memberClass.getAccessFlags())) {
156             isSameClassPackage = isSameClassPackage(currentClass, memberClass);
157             gotIsSameClassPackage = true;
158             if (!isSameClassPackage) {
159                 return false;
160             }
161         }
162 
163         // At this point we know that currentClass can access memberClass.
164 
165         if (Modifier.isPublic(modifiers)) {
166             return true;
167         }
168 
169         boolean successSoFar = false;
170 
171         if (Modifier.isProtected(modifiers)) {
172             // See if currentClass is a subclass of memberClass
173             if (isSubclassOf(currentClass, memberClass)) {
174                 successSoFar = true;
175             }
176         }
177 
178         if (!successSoFar && !Modifier.isPrivate(modifiers)) {
179             if (!gotIsSameClassPackage) {
180                 isSameClassPackage = isSameClassPackage(currentClass,
181                                                         memberClass);
182                 gotIsSameClassPackage = true;
183             }
184 
185             if (isSameClassPackage) {
186                 successSoFar = true;
187             }
188         }
189 
190         if (!successSoFar) {
191             return false;
192         }
193 
194         if (Modifier.isProtected(modifiers)) {
195             // Additional test for protected members: JLS 6.6.2
196             Class<?> targetClass = (target == null ? memberClass : target.getClass());
197             if (targetClass != currentClass) {
198                 if (!gotIsSameClassPackage) {
199                     isSameClassPackage = isSameClassPackage(currentClass, memberClass);
200                     gotIsSameClassPackage = true;
201                 }
202                 if (!isSameClassPackage) {
203                     if (!isSubclassOf(targetClass, currentClass)) {
204                         return false;
205                     }
206                 }
207             }
208         }
209 
210         return true;
211     }
212 
isSameClassPackage(Class<?> c1, Class<?> c2)213     private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {
214         return isSameClassPackage(c1.getClassLoader(), c1.getName(),
215                                   c2.getClassLoader(), c2.getName());
216     }
217 
218     /** Returns true if two classes are in the same package; classloader
219         and classname information is enough to determine a class's package */
isSameClassPackage(ClassLoader loader1, String name1, ClassLoader loader2, String name2)220     private static boolean isSameClassPackage(ClassLoader loader1, String name1,
221                                               ClassLoader loader2, String name2)
222     {
223         if (loader1 != loader2) {
224             return false;
225         } else {
226             int lastDot1 = name1.lastIndexOf('.');
227             int lastDot2 = name2.lastIndexOf('.');
228             if ((lastDot1 == -1) || (lastDot2 == -1)) {
229                 // One of the two doesn't have a package.  Only return true
230                 // if the other one also doesn't have a package.
231                 return (lastDot1 == lastDot2);
232             } else {
233                 int idx1 = 0;
234                 int idx2 = 0;
235 
236                 // Skip over '['s
237                 if (name1.charAt(idx1) == '[') {
238                     do {
239                         idx1++;
240                     } while (name1.charAt(idx1) == '[');
241                     if (name1.charAt(idx1) != 'L') {
242                         // Something is terribly wrong.  Shouldn't be here.
243                         throw new InternalError("Illegal class name " + name1);
244                     }
245                 }
246                 if (name2.charAt(idx2) == '[') {
247                     do {
248                         idx2++;
249                     } while (name2.charAt(idx2) == '[');
250                     if (name2.charAt(idx2) != 'L') {
251                         // Something is terribly wrong.  Shouldn't be here.
252                         throw new InternalError("Illegal class name " + name2);
253                     }
254                 }
255 
256                 // Check that package part is identical
257                 int length1 = lastDot1 - idx1;
258                 int length2 = lastDot2 - idx2;
259 
260                 if (length1 != length2) {
261                     return false;
262                 }
263                 return name1.regionMatches(false, idx1, name2, idx2, length1);
264             }
265         }
266     }
267 
isSubclassOf(Class<?> queryClass, Class<?> ofClass)268     static boolean isSubclassOf(Class<?> queryClass,
269                                 Class<?> ofClass)
270     {
271         while (queryClass != null) {
272             if (queryClass == ofClass) {
273                 return true;
274             }
275             queryClass = queryClass.getSuperclass();
276         }
277         return false;
278     }
279 
280     // Android-removed: Dead code.
281 
282 }
283