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 sun.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