2012-08-02 15 views
5

Prima di tutto ho visto Load Java-Byte-Code at Runtime ed è stato utile per arrivare a me nello stesso punto in cui sono bloccato al momento.Come caricare una classe da un array di byte in Android?

Sto provando a caricare una classe da un array di byte per evitare di archiviare un file su disco. Per scopi di test in questo esempio sto semplicemente leggendo in un file .class in un array di byte, quindi ovviamente il file è ancora memorizzato su disco, ma è solo per vedere se il codice può funzionare.

Prendo questo array di byte e quindi utilizzo un ClassLoader personalizzato con il metodo loadClass per caricare una classe, ma non funziona.

byte[] bytearray = null; 
    try{  
    RandomAccessFile f = new RandomAccessFile("/sdcard/ClassToGet.dex", "r"); 
    bytearray = new byte[(int) f.length()]; 
    f.read(bytearray); 

    MyClassLoader classloader = new MyClassLoader(); 
    classloader.setBuffer(bytearray); 
    classloader.loadClass("com.pack.ClassIWant"); 
    } 

Ecco l'attuazione ClassLoader:

public class MyClassLoader extends DexClassLoader { 

private byte[] buffer; 

    @Override 
    public Class findClass(String className){ 
    byte[] b = getBuffer(); 
    return this.defineClass(className, b, 0, b.length); 
    } 

public void setBuffer(byte[] b){ 
    buffer = b; 
} 
public byte[] getBuffer(){ 
    return buffer; 
} 

E l'errore che sto ricevendo è questo:

java.lang.UnsupportedOperationException: non può caricare questo tipo di file di classe a java.lang.VMClassLoader.defineClass (metodo nativo)

L'ho fornito con file .class, file .dex, .apk, .jar, ecc ... Non ho idea di cosa t "tipo di file di classe" vuole da me e la documentazione su di esso è inesistente. Qualsiasi aiuto sarebbe fantastico. Ho cercato di ottenere questo lavoro per quattro giorni di seguito.

+0

http://stackoverflow.com/a/3024261/61855 – theomega

+0

sto ancora ricevendo lo stesso messaggio di errore di "UnsupportedOperationException", anche utilizzando i file DEX file/vaso. Cosa hai fatto nel tuo esempio? – HumanCentipedeLinkedList

+0

Chi stai frequentando? Me? Se fai riferimento alla mia domanda che hai collegato: non stavo usando Android per questo progetto, quindi non ci sono problemi lì. – theomega

risposta

1

Assicurarsi che il file di .dex è una vera e propria dx-prodotto Dalvik eseguibile e non è un file Java .class sotto mentite spoglie. Se si utilizza l'estensione .dex, il file deve essere un file .dex; altrimenti utilizzare l'estensione .jar per un file ZIP contenente una voce classes.dex.

Non tutte le versioni di Dalvik possono caricare classi dalla memoria. È possibile aggirare questo caricando la classe dal file system. C'è un esempio in DexMaker'sgenerateAndLoad metodo:

byte[] dex = ... 

    /* 
    * This implementation currently dumps the dex to the filesystem. It 
    * jars the emitted .dex for the benefit of Gingerbread and earlier 
    * devices, which can't load .dex files directly. 
    * 
    * TODO: load the dex from memory where supported. 
    */ 
    File result = File.createTempFile("Generated", ".jar", dexCache); 
    result.deleteOnExit(); 
    JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result)); 
    jarOut.putNextEntry(new JarEntry(DexFormat.DEX_IN_JAR_NAME)); 
    jarOut.write(dex); 
    jarOut.closeEntry(); 
    jarOut.close(); 
    try { 
     return (ClassLoader) Class.forName("dalvik.system.DexClassLoader") 
       .getConstructor(String.class, String.class, String.class, ClassLoader.class) 
       .newInstance(result.getPath(), dexCache.getAbsolutePath(), null, parent); 
    } catch (ClassNotFoundException e) { 
     throw new UnsupportedOperationException("load() requires a Dalvik VM", e); 
    } catch (InvocationTargetException e) { 
     throw new RuntimeException(e.getCause()); 
    } catch (InstantiationException e) { 
     throw new AssertionError(); 
    } catch (NoSuchMethodException e) { 
     throw new AssertionError(); 
    } catch (IllegalAccessException e) { 
     throw new AssertionError(); 
    } 
0

Android non esegue il bytecode JVM, ma il bytecode Dalvik. Quindi, l'operazione dovrebbe includere questa linea prima defineClass()

context.setOptimizationLevel(-1); 
+0

Potresti entrare in un piccolo dettaglio su cosa lo fa/come usarlo? Gli unici esempi che vedo da una rapida ricerca su google stanno usando Rhino che non sto usando. Perché il caricamento di un file .dex non dovrebbe essere sufficiente al posto di .class? – HumanCentipedeLinkedList

+0

Ho esaminato ancora un po 'e ho notato [questo] (http://stackoverflow.com/questions/3022454/how-to-load-a-java-class-dynamically-on-android-dalvik) risposta su SO. Scommetto che ti aiuterebbe. Dovrai memorizzarlo come .dex – tolgap

+0

Continuo a ricevere lo stesso errore di "UnsupportedOperationException: impossibile caricare questo tipo di file di classe" anche per i file .dex. Ho provato .class, .dex, .apk e .jar e nessuno funziona. Che cosa sto facendo di sbagliato? – HumanCentipedeLinkedList

2

Ho lo stesso problema che avete.

Il motivo per cui viene visualizzato l'errore "impossibile caricare questo tipo di file di classe" è semplice.

Nell'origine della piattaforma, "/dalvik/vm/native/java_lang_VMClassLoader.cpp" che è correlato al metodo "defineClass" restituisce sempre un'eccezione come segue. (versione: ICS)

Infine, sono giunto alla conclusione che non è possibile caricare .dex in formato array di byte.

C'è qualcuno che può caricare .dex utilizzando l'array di byte? (Non utilizzando i file)

/* 
* static Class defineClass(ClassLoader cl, String name, 
*  byte[] data, int offset, int len) 
*  throws ClassFormatError 
* 
* Convert an array of bytes to a Class object. 
*/ 
static void Dalvik_java_lang_VMClassLoader_defineClass(const u4* args, JValue* pResult) 
{ 
    Object* loader = (Object*) args[0]; 
    StringObject* nameObj = (StringObject*) args[1]; 
    const u1* data = (const u1*) args[2]; 
    int offset = args[3]; 
    int len = args[4]; 
    char* name = NULL; 

    name = dvmCreateCstrFromString(nameObj); 
    ALOGE("ERROR: defineClass(%p, %s, %p, %d, %d)", 
     loader, name, data, offset, len); 
    dvmThrowUnsupportedOperationException(
     "can't load this type of class file"); 

    free(name); 
    RETURN_VOID(); 
} 

/* 
* static Class defineClass(ClassLoader cl, byte[] data, int offset, 
*  int len) 
*  throws ClassFormatError 
* 
* Convert an array of bytes to a Class object. Deprecated version of 
* previous method, lacks name parameter. 
*/ 
static void Dalvik_java_lang_VMClassLoader_defineClass2(const u4* args, JValue* pResult) 
{ 
    Object* loader = (Object*) args[0]; 
    const u1* data = (const u1*) args[1]; 
    int offset = args[2]; 
    int len = args[3]; 

    ALOGE("ERROR: defineClass(%p, %p, %d, %d)", 
     loader, data, offset, len); 
    dvmThrowUnsupportedOperationException(
     "can't load this type of class file"); 

    RETURN_VOID(); 
} 
+0

Guardando quel codice sembra che defineClass ALWAYS getta l'eccezione dell'operazione non supportata indipendentemente dall'input, che è in sintonia con quello che hai detto. Se questo è il motivo per cui anche permetterlo nell'API ?? – HumanCentipedeLinkedList

Problemi correlati