Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Android classloader allow reflective access to the public field of a package-private class from another package?

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 ?)

like image 502
desseim Avatar asked Oct 11 '15 00:10

desseim


People also ask

What is ClassLoader in Android?

This class loader is used to load classes and resources from a search path of URLs referring to both JAR files and directories. A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class.

How to create object of a class using reflection in java?

We can use newInstance() method on the constructor object to instantiate a new instance of the class. Since we use reflection when we don't have the classes information at compile time, we can assign it to Object and then further use reflection to access it's fields and invoke it's methods.

How can you directly access all classes in the package in Java?

Since Java enforces the most restrictive access, we have to explicitly declare packages using the export or open module declaration to get reflective access to the classes inside the module.

Can you find all classes in a package using reflection?

If there are classes that get generated, or delivered remotely, you will not be able to discover those classes. The normal method is instead to somewhere register the classes you need access to in a file, or reference them in a different class. Or just use convention when it comes to naming.


1 Answers

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.

like image 194
wero Avatar answered Oct 12 '22 01:10

wero