| Index: services/android/java/src/org/chromium/services/android/JavaHandler.java
 | 
| diff --git a/services/android/java/src/org/chromium/services/android/JavaHandler.java b/services/android/java/src/org/chromium/services/android/JavaHandler.java
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..7abdcf402c93245bdd87314e36e310585097d2d7
 | 
| --- /dev/null
 | 
| +++ b/services/android/java/src/org/chromium/services/android/JavaHandler.java
 | 
| @@ -0,0 +1,141 @@
 | 
| +// Copyright 2015 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +package org.chromium.services.android;
 | 
| +
 | 
| +import android.content.Context;
 | 
| +import android.util.Log;
 | 
| +
 | 
| +import dalvik.system.DexClassLoader;
 | 
| +
 | 
| +import org.chromium.base.CalledByNative;
 | 
| +import org.chromium.base.JNINamespace;
 | 
| +import org.chromium.mojo.system.Core;
 | 
| +import org.chromium.mojo.system.MessagePipeHandle;
 | 
| +import org.chromium.mojo.system.impl.CoreImpl;
 | 
| +
 | 
| +import java.io.File;
 | 
| +import java.io.IOException;
 | 
| +import java.lang.reflect.Method;
 | 
| +import java.util.jar.JarFile;
 | 
| +import java.util.jar.Manifest;
 | 
| +
 | 
| +/**
 | 
| + * Content handler for Android Java code.
 | 
| + */
 | 
| +@JNINamespace("services::android")
 | 
| +public class JavaHandler {
 | 
| +    private static final String TAG = "JavaHandler";
 | 
| +
 | 
| +    // File extensions used to identify application libraries in the provided
 | 
| +    // archive.
 | 
| +    private static final String JAVA_LIBRARY_SUFFIX = ".dex.jar";
 | 
| +    // Filename sections used for naming temporary files holding application
 | 
| +    // files.
 | 
| +    private static final String ARCHIVE_PREFIX = "archive";
 | 
| +
 | 
| +    // Directories used to hold temporary files. These are cleared when
 | 
| +    // clearTemporaryFiles() is called.
 | 
| +    private static final String DEX_OUTPUT_DIRECTORY = "dex_output";
 | 
| +    private static final String APP_DIRECTORY = "applications";
 | 
| +
 | 
| +    private static final int BUFFER_SIZE = 1024;
 | 
| +
 | 
| +    /**
 | 
| +     * Deletes directories holding the temporary files.
 | 
| +     */
 | 
| +    private static void clearTemporaryFiles(Context context, File archive) {
 | 
| +        deleteRecursively(getDexOutputDir(context));
 | 
| +        deleteRecursively(archive);
 | 
| +    }
 | 
| +
 | 
| +    /**
 | 
| +     * Deletes a file or directory. Directory will be deleted even if not empty.
 | 
| +     */
 | 
| +    private static void deleteRecursively(File file) {
 | 
| +        if (file.isDirectory()) {
 | 
| +            for (File child : file.listFiles()) {
 | 
| +                deleteRecursively(child);
 | 
| +            }
 | 
| +        }
 | 
| +        file.delete();
 | 
| +    }
 | 
| +
 | 
| +    /**
 | 
| +     * Returns the path at which the native part should save the application archive.
 | 
| +     */
 | 
| +    @CalledByNative
 | 
| +    private static String getNewTempLibraryPath(Context context) throws IOException {
 | 
| +        return File.createTempFile(ARCHIVE_PREFIX, JAVA_LIBRARY_SUFFIX, getAppDir(context))
 | 
| +                .getAbsolutePath();
 | 
| +    }
 | 
| +
 | 
| +    /**
 | 
| +     * Extracts and runs the application libraries contained by the indicated archive.
 | 
| +     *
 | 
| +     * @param context the application context
 | 
| +     * @param archivePath the path of the archive containing the application to be run
 | 
| +     * @param handle handle to the shell to be passed to the native application. On the Java side
 | 
| +     *        this is opaque payload.
 | 
| +     * @param runApplicationPtr pointer to the function that will set the native thunks and call
 | 
| +     *        into the application MojoMain. On the Java side this is opaque payload.
 | 
| +     */
 | 
| +    @CalledByNative
 | 
| +    private static boolean bootstrap(Context context, String archivePath,
 | 
| +            int applicationRequestHandle) {
 | 
| +        File application_java_library = new File(archivePath);
 | 
| +
 | 
| +        String dexPath = application_java_library.getAbsolutePath();
 | 
| +        DexClassLoader bootstrapLoader = new DexClassLoader(dexPath,
 | 
| +                getDexOutputDir(context).getAbsolutePath(), null,
 | 
| +                JavaHandler.class.getClassLoader());
 | 
| +
 | 
| +        // The starting Mojo class is a class implementing a static MojoMain
 | 
| +        // method. Its name
 | 
| +        // is defined in the .jar manifest file, like a .jar defines a
 | 
| +        // Main-Class attribute for
 | 
| +        // the starting point of a standalone java application.
 | 
| +        String mojoClass;
 | 
| +        try {
 | 
| +            try {
 | 
| +                JarFile jar = new JarFile(application_java_library);
 | 
| +                Manifest manifest = jar.getManifest();
 | 
| +                mojoClass = manifest.getMainAttributes().getValue("Mojo-Class");
 | 
| +            } catch (IOException e) {
 | 
| +                Log.e(TAG, "Unable to extract Manifest attributes", e);
 | 
| +                return false;
 | 
| +            }
 | 
| +
 | 
| +            if (mojoClass == null) {
 | 
| +                Log.e(TAG, "Mojo-Class class not found");
 | 
| +                return false;
 | 
| +            }
 | 
| +
 | 
| +            Core core = CoreImpl.getInstance();
 | 
| +            MessagePipeHandle handle =
 | 
| +                    core.acquireNativeHandle(applicationRequestHandle).toMessagePipeHandle();
 | 
| +            try {
 | 
| +                Class<?> loadedClass = bootstrapLoader.loadClass(mojoClass);
 | 
| +                Method mojoMain =
 | 
| +                        loadedClass.getMethod("mojoMain", Context.class, Core.class,
 | 
| +                                MessagePipeHandle.class);
 | 
| +                mojoMain.invoke(null, context, core, handle);
 | 
| +            } catch (Throwable t) {
 | 
| +                Log.e(TAG, "Running MojoMain failed.", t);
 | 
| +                return false;
 | 
| +            }
 | 
| +        } finally {
 | 
| +            clearTemporaryFiles(context, application_java_library);
 | 
| +        }
 | 
| +        return true;
 | 
| +    }
 | 
| +
 | 
| +    private static File getDexOutputDir(Context context) {
 | 
| +        return context.getDir(DEX_OUTPUT_DIRECTORY, Context.MODE_PRIVATE);
 | 
| +    }
 | 
| +
 | 
| +    private static File getAppDir(Context context) {
 | 
| +        return context.getDir(APP_DIRECTORY, Context.MODE_PRIVATE);
 | 
| +    }
 | 
| +}
 | 
| 
 |