Index: shell/android/apk/src/org/chromium/mojo/shell/AndroidHandler.java |
diff --git a/shell/android/apk/src/org/chromium/mojo/shell/AndroidHandler.java b/shell/android/apk/src/org/chromium/mojo/shell/AndroidHandler.java |
index 138ed5a109c8db6411a4b63180f1e8307bad107a..9719f1902e18f05f2cd55512860535e6a7ae382d 100644 |
--- a/shell/android/apk/src/org/chromium/mojo/shell/AndroidHandler.java |
+++ b/shell/android/apk/src/org/chromium/mojo/shell/AndroidHandler.java |
@@ -14,7 +14,6 @@ import org.chromium.base.JNINamespace; |
import org.chromium.base.TraceEvent; |
import java.io.File; |
-import java.io.IOException; |
import java.lang.reflect.Constructor; |
/** |
@@ -36,33 +35,19 @@ public class AndroidHandler { |
// File extensions used to identify application libraries in the provided archive. |
private static final String JAVA_LIBRARY_SUFFIX = ".dex.jar"; |
private static final String NATIVE_LIBRARY_SUFFIX = ".so"; |
- // Filename sections used for naming temporary files holding application files. |
- private static final String ARCHIVE_PREFIX = "archive"; |
- private static final String ARCHIVE_SUFFIX = ".zip"; |
- // 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 String ASSET_DIRECTORY = "assets"; |
- |
- /** |
- * Deletes directories holding the temporary files. This should be called early on shell startup |
- * to clean up after the previous run. |
- */ |
- static void clearTemporaryFiles(Context context) { |
- FileHelper.deleteRecursively(getDexOutputDir(context)); |
- FileHelper.deleteRecursively(getAppDir(context)); |
- FileHelper.deleteRecursively(getAssetDir(context)); |
- } |
- |
- /** |
- * Returns the path at which the native part should save the application archive. |
- */ |
- @CalledByNative |
- private static String getNewTempArchivePath(Context context) throws IOException { |
- return File.createTempFile(ARCHIVE_PREFIX, ARCHIVE_SUFFIX, |
- getAppDir(context)).getAbsolutePath(); |
+ // Recursively finds the first file in |dir| whose name ends with |suffix|. Returns |null| if |
+ // none is found. |
+ static File find(File dir, String suffix) { |
+ for (File child : dir.listFiles()) { |
+ if (child.isDirectory()) { |
+ File result = find(child, suffix); |
+ if (result != null) return result; |
+ } else { |
+ if (child.getName().endsWith(suffix)) return child; |
+ } |
+ } |
+ return null; |
} |
/** |
@@ -70,56 +55,59 @@ public class AndroidHandler { |
* |
* @param context the application context |
* @param tracingId opaque id, used for tracing. |
- * @param archivePath the path of the archive containing the application to be run |
+ * @param extractedPath the path of the directory containing the application to be run |
+ * @param cachePath the path of a cache directory that can be used to extract assets |
* @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, long tracingId, String archivePath, |
- int handle, long runApplicationPtr) { |
- File bootstrap_java_library; |
- File bootstrap_native_library; |
- try { |
- TraceEvent.begin("ExtractBootstrapJavaLibrary"); |
- bootstrap_java_library = FileHelper.extractFromAssets(context, BOOTSTRAP_JAVA_LIBRARY, |
- getAssetDir(context), true); |
- TraceEvent.end("ExtractBootstrapJavaLibrary"); |
- TraceEvent.begin("ExtractBootstrapNativeLibrary"); |
- bootstrap_native_library = FileHelper.extractFromAssets(context, |
- BOOTSTRAP_NATIVE_LIBRARY, getAssetDir(context), true); |
- TraceEvent.end("ExtractBootstrapNativeLibrary"); |
- } catch (Exception e) { |
- Log.e(TAG, "Extraction of bootstrap files from assets failed.", e); |
- return false; |
- } |
- |
- File application_java_library; |
- File application_native_library; |
- try { |
- File archive = new File(archivePath); |
- TraceEvent.begin("ExtractApplicationJavaLibrary"); |
- application_java_library = FileHelper.extractFromArchive(archive, JAVA_LIBRARY_SUFFIX, |
- getAppDir(context)); |
- TraceEvent.end("ExtractApplicationJavaLibrary"); |
- TraceEvent.begin("ExtractApplicationNativeLibrary"); |
- application_native_library = FileHelper.extractFromArchive(archive, |
- NATIVE_LIBRARY_SUFFIX, getAppDir(context)); |
- TraceEvent.end("ExtractApplicationNativeLibrary"); |
- } catch (Exception e) { |
- Log.e(TAG, "Extraction of application files from the archive failed.", e); |
- return false; |
+ private static boolean bootstrap(Context context, long tracingId, String extractedPath, |
+ String cachePath, int handle, long runApplicationPtr) { |
+ File extractedDir = new File(extractedPath); |
+ File cacheDir = new File(cachePath); |
+ File compiledDexDir = new File(cacheDir, "dex"); |
+ File assetDir = new File(cacheDir, "asset"); |
+ assetDir.mkdirs(); |
+ File preparedSentinel = new File(cacheDir, "prepared"); |
+ |
+ // If the sentinel doesn't exist, extract the assets from the apk. |
+ if (!preparedSentinel.exists()) { |
+ compiledDexDir.mkdirs(); |
+ try { |
+ TraceEvent.begin("ExtractBootstrapJavaLibrary"); |
+ FileHelper.extractFromAssets(context, BOOTSTRAP_JAVA_LIBRARY, assetDir, false); |
+ TraceEvent.end("ExtractBootstrapJavaLibrary"); |
+ TraceEvent.begin("ExtractBootstrapNativeLibrary"); |
+ FileHelper.extractFromAssets(context, BOOTSTRAP_NATIVE_LIBRARY, assetDir, false); |
+ TraceEvent.end("ExtractBootstrapNativeLibrary"); |
+ TraceEvent.begin("MoveBootstrapNativeLibrary"); |
+ // Rename the bootstrap library to prevent dlopen to think it is alread opened. |
+ new File(assetDir, BOOTSTRAP_NATIVE_LIBRARY) |
+ .renameTo(File.createTempFile("bootstrap", ".so", assetDir)); |
+ TraceEvent.end("MoveBootstrapNativeLibrary"); |
+ new java.io.FileOutputStream(preparedSentinel).close(); |
+ } catch (Exception e) { |
+ Log.e(TAG, "Extraction of bootstrap files from assets failed.", e); |
+ return false; |
+ } |
} |
+ // Find the 4 files needed to execute the android application. |
+ File bootstrap_java_library = new File(assetDir, BOOTSTRAP_JAVA_LIBRARY); |
+ File bootstrap_native_library = find(assetDir, NATIVE_LIBRARY_SUFFIX); |
+ File application_java_library = find(extractedDir, JAVA_LIBRARY_SUFFIX); |
+ File application_native_library = find(extractedDir, NATIVE_LIBRARY_SUFFIX); |
+ // Compile the java files. |
String dexPath = bootstrap_java_library.getAbsolutePath() + File.pathSeparator |
+ application_java_library.getAbsolutePath(); |
TraceEvent.begin("CreateDexClassLoader"); |
DexClassLoader bootstrapLoader = new DexClassLoader(dexPath, |
- getDexOutputDir(context).getAbsolutePath(), null, |
- ClassLoader.getSystemClassLoader()); |
+ compiledDexDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader()); |
TraceEvent.end("CreateDexClassLoader"); |
+ // Create the instance of the Bootstrap class from the compiled java file and run it. |
try { |
Class<?> loadedClass = bootstrapLoader.loadClass(BOOTSTRAP_CLASS); |
Class<? extends Runnable> bootstrapClass = loadedClass.asSubclass(Runnable.class); |
@@ -136,15 +124,4 @@ public class AndroidHandler { |
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); |
- } |
- |
- private static File getAssetDir(Context context) { |
- return context.getDir(ASSET_DIRECTORY, Context.MODE_PRIVATE); |
- } |
} |