Почему Android-загрузчик классов допускает отражающий доступ к публичному полю пакета-частного класса из другого пакета?

Похоже, что загрузчик классов приложений Android позволяет рефлексивно получить ссылку на поле public static класса private-private даже из другого пакета (чем тот, который указан выше в этом классе), в то время как загрузчик классов Java JDK например, нет.

Более конкретно, учитывая следующее определение класса:

package org.example.a

class PackagePrivateClass {
    public static final Parcelable.Creator<PackagePrivateClass> CREATOR = generateCreator();
}

И следующий код в отдельном пакете:

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

При выполнении в Sun JVM он выдает IllegalAccessException в последней строке:

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

Однако при запуске на Android-устройстве (5.1 Lollipop FWIW) он выполняется без металирования, а creatorFieldRef.get(null) фактически возвращает действительную ссылку на поле CREATOR.

Мой вопрос: почему это так? Это ошибка или особенность загрузчика классов Android? (или, если применимо, что я ошибся в моем примере?)

Ответ 1

Кажется, что это ошибка в runtime для Android, которая была исправлена ​​в этом commit:

Добавить проверки доступа к отражению метода и поля.

До этого фиксации можно было беспрепятственно обращаться к полям посредством отражения или даже устанавливать значение окончательных полей.

Проверка доступа теперь реализована в функциях времени выполнения ValidateFieldAccess и ValidateAccess.