2015-10-11 18 views
10

Sembra che il programma di caricamento classe dell'applicazione Android consenta di acquisire in modo riflessivo un riferimento al campo public static di una classe pacchetto-privato anche da un pacchetto diverso (rispetto a quello in cui è definita la classe summenzionata), mentre il classloader Sun JDK ad esempio non esegue 't.Perché il classloader di Android consente l'accesso riflessivo al campo pubblico di una classe di pacchetto privata da un altro pacchetto?

Più concretamente, data la seguente definizione di classe:

package org.example.a 

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

E il seguente codice in un pacchetto separato:

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

Quando eseguito su Sun JVM viene generata IllegalAccessException sull'ultima riga:

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

Tuttavia, quando eseguito su un dispositivo Android (5.1 Lollipo p FWIW) viene eseguito senza lancio e creatorFieldRef.get(null) restituisce effettivamente un riferimento valido al campo CREATOR.

La mia domanda è: perché è così? È un bug o una funzionalità del classloader Android ?? (o, se del caso, quello che ho ricevuto di sbagliato nel mio esempio?)

risposta

2

sembra che sia un bug nel runtime di Android che è stato risolto in questo commit:

Aggiungi controlli di accesso al metodo e Campo di riflessione

Prima di questo commit era possibile accedere ai campi tramite riflessione in modo illimitato o impostare anche the value of final fields.

Il controllo di accesso è now implementato nelle funzioni di runtime ValidateFieldAccess e ValidateAccess.

+0

Buona cattura e il codice di commit sembra davvero come se rifiutasse l'accesso ai campi di classi non pubbliche in un pacchetto diverso, ma sebbene il commit risolva un bug specifico per ART e sia incluso da Lollipop (cioè dovrebbe solo riprodurre su KitKat ART), il codice di esempio nella mia domanda non gira su nessuna macchina virtuale Android, Dalvik e (più recente) ART. Mi hai convinto che potrebbe essere un bug, quindi ho inviato un [problema ad AOSP] (https://code.google.com/p/android/issues/detail?id=191727), vedremo se è intenzionale o no. Grazie. – desseim