Android Open Source - grooidshell-example Grooid Shell






From Project

Back to project page grooidshell-example.

License

The source code is released under:

Apache License

If you think the Android project grooidshell-example listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package me.champeau.groovydroid;
/*from  w w w.  j  av  a  2 s. c om*/
import android.util.Log;

import com.android.dx.Version;
import com.android.dx.dex.DexFormat;
import com.android.dx.dex.DexOptions;
import com.android.dx.dex.cf.CfOptions;
import com.android.dx.dex.cf.CfTranslator;
import com.android.dx.dex.code.PositionList;
import com.android.dx.dex.file.ClassDefItem;
import com.android.dx.dex.file.DexFile;

import org.codehaus.groovy.control.BytecodeProcessor;
import org.codehaus.groovy.control.CompilerConfiguration;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import dalvik.system.DexClassLoader;
import groovy.lang.GrooidClassLoader;
import groovy.lang.Script;

/**
 * A shell capable of executing Groovy scripts at runtime, on an Android device.
 *
 * @author Cdric Champeau
 */
public class GrooidShell {

    private static final String DEX_IN_JAR_NAME = "classes.dex";
    private static final Attributes.Name CREATED_BY = new Attributes.Name("Created-By");

    private final DexOptions dexOptions;
    private final CfOptions cfOptions;

    private final File tmpDynamicFiles;
    private final ClassLoader classLoader;

    public GrooidShell(File tmpDir, ClassLoader parent) {
        tmpDynamicFiles = tmpDir;
        classLoader = parent;
        dexOptions = new DexOptions();
        dexOptions.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
        cfOptions = new CfOptions();
        cfOptions.positionInfo = PositionList.LINES;
        cfOptions.localInfo = true;
        cfOptions.strictNameCheck = true;
        cfOptions.optimize = false;
        cfOptions.optimizeListFile = null;
        cfOptions.dontOptimizeListFile = null;
        cfOptions.statistics = false;
    }


    public EvalResult evaluate(String scriptText) {
        long sd = System.nanoTime();
        final Set<String> classNames = new LinkedHashSet<String>();
        final DexFile dexFile = new DexFile(dexOptions);
        CompilerConfiguration config = new CompilerConfiguration();
        config.setBytecodePostprocessor(new BytecodeProcessor() {
            @Override
            public byte[] processBytecode(String s, byte[] bytes) {
                ClassDefItem classDefItem = CfTranslator.translate(s+".class", bytes, cfOptions, dexOptions);
                dexFile.add(classDefItem);
                classNames.add(s);
                return bytes;
            }
        });

        GrooidClassLoader gcl = new GrooidClassLoader(this.classLoader, config);
        try {
            gcl.parseClass(scriptText);
        }  catch (Throwable e) {
            Log.e("GrooidShell","Dynamic loading failed!",e);
        }
        byte[] dalvikBytecode = new byte[0];
        try {
            dalvikBytecode = dexFile.toDex(new OutputStreamWriter(new ByteArrayOutputStream()), false);
        } catch (IOException e) {
            Log.e("GrooidShell", "Unable to convert to Dalvik", e);
        }

        Map<String, Class> classes = defineDynamic(classNames, dalvikBytecode);
        long compilationTime = System.nanoTime()-sd;
        long execTime = 0;
        Object result = null;
        for (Class scriptClass : classes.values()) {
            if (Script.class.isAssignableFrom(scriptClass)) {
                sd = System.nanoTime();
                Script script = null;
                try {
                    script = (Script) scriptClass.newInstance();
                } catch (InstantiationException e) {
                    Log.e("GroovyDroidShell", "Unable to create script",e);
                } catch (IllegalAccessException e) {
                    Log.e("GroovyDroidShell", "Unable to create script", e);
                }
                result = script.run();
                execTime = System.nanoTime()-sd;
                break;
            }
        }
        return new EvalResult(compilationTime, execTime, result);
    }


    private Map<String,Class> defineDynamic(Set<String> classNames, byte[] dalvikBytecode) {
        File tmpDex = new File(tmpDynamicFiles, UUID.randomUUID().toString()+".jar");
        Map<String,Class> result = new LinkedHashMap<String, Class>();
        try {
            FileOutputStream fos = new FileOutputStream(tmpDex);
            JarOutputStream jar = new JarOutputStream(fos, makeManifest());
            JarEntry classes = new JarEntry(DEX_IN_JAR_NAME);
            classes.setSize(dalvikBytecode.length);
            jar.putNextEntry(classes);
            jar.write(dalvikBytecode);
            jar.closeEntry();
            jar.finish();
            jar.flush();
            fos.flush();
            fos.close();
            jar.close();
            DexClassLoader loader = new DexClassLoader(tmpDex.getAbsolutePath(), tmpDynamicFiles.getAbsolutePath(), null, classLoader);
            for (String className : classNames) {
                result.put(className, loader.loadClass(className));
            }
            return result;
        } catch (Throwable e) {
            Log.e("DynamicLoading", "Unable to load class",e);
        } finally {
            tmpDex.delete();
        }
        return null;
    }

    private static Manifest makeManifest() throws IOException {
        Manifest manifest = new Manifest();
        Attributes attribs = manifest.getMainAttributes();
        attribs.put(Attributes.Name.MANIFEST_VERSION, "1.0");
        attribs.put(CREATED_BY, "dx " + Version.VERSION);
        attribs.putValue("Dex-Location", DEX_IN_JAR_NAME);
        return manifest;
    }

    public static class EvalResult {
        final long compilationTime;
        final long execTime;
        final Object result;

        public EvalResult(long compilationTime, long execTime, Object result) {
            this.compilationTime = compilationTime;
            this.execTime = execTime;
            this.result = result;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("Compilation time = ").append(compilationTime / 1000000).append("ms");
            sb.append("\n");
            sb.append("Execution time = ").append(execTime / 1000000).append("ms");
            sb.append("\n");
            sb.append("Result = ").append(result);
            return sb.toString();
        }
    }

}




Java Source Code List

groovy.lang.GrooidClassLoader.java
me.champeau.groovydroid.GrooidShell.java
me.champeau.groovydroid.util.SystemUiHiderBase.java
me.champeau.groovydroid.util.SystemUiHiderHoneycomb.java
me.champeau.groovydroid.util.SystemUiHider.java