Reputation: 8248
It seems that the Android application class loader allows to reflectively acquire a reference to the public static
field of a package-private class even from a different package (than the one the aforementioned class is defined in), while Sun JDK classloader for example doesn't.
More concretely, given the following class definition:
package org.example.a
class PackagePrivateClass {
public static final Parcelable.Creator<PackagePrivateClass> CREATOR = generateCreator();
}
And the following code in a separate package:
package org.example.b
public class TestClass {
public void testMethod() {
final Class classRef = Class.forName("org.example.a.PackagePrivateClass");
final Field creatorFieldRef = classRef.getField("CREATOR");
creatorFieldRef.get(null); // throws here (unless on Android)
}
}
When executed on Sun JVM it throws an IllegalAccessException
on the last line:
java.lang.IllegalAccessException: Class org.example.b.TestClass can not access a member of class org.example.a.PackagePrivateClass with modifiers "public static final"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
...
However, when run on an Android device (5.1 Lollipop FWIW) it executes without throwing and creatorFieldRef.get(null)
actually returns a valid reference to the CREATOR
field.
My question is : why is it the case ? Is it a bug or a feature of the Android classloader ?? (or, if applicable, what did I get wrong in my example ?)
Upvotes: 10
Views: 434
Reputation: 33000
Seems that it is a bug in the android runtime which was fixed in this commit:
Add access checks to Method and Field reflection.
Prior to this commit it was possible to access fields via reflection in an unrestricted way or even set the value of final fields.
The access check is now implemented in the runtime functions ValidateFieldAccess
and ValidateAccess
.
Upvotes: 2