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