Skip to content

Commit

Permalink
Revert of Changes caching logic of mojo java apps (patchset #5 id:800…
Browse files Browse the repository at this point in the history
…01 of https://codereview.chromium.org/1149813002/)

Reason for revert:
Broke windows build.

Original issue's description:
> Changes caching logic of mojo java apps
>
> Previously we would extract all necessary files every time we ran the
> app. This is obviously unnecessary for any bundled apps. Now we
> extract only as necessary.
>
> R=ben@chromium.org, jcivelli@chromium.org
> BUG=none
> TEST=none
>
> Committed: https://crrev.com/128f7a0181634a89a35f681baab1d086d100e377
> Cr-Commit-Position: refs/heads/master@{#330824}

TBR=ben@chromium.org,jcivelli@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=none

Review URL: https://codereview.chromium.org/1147203002

Cr-Commit-Position: refs/heads/master@{#330832}
  • Loading branch information
sky authored and Commit bot committed May 20, 2015
1 parent 11433b2 commit f8e1299
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 354 deletions.
80 changes: 4 additions & 76 deletions mojo/runner/android/android_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
#include "mojo/public/c/system/main.h"
#include "mojo/runner/android/run_android_application_function.h"
#include "mojo/runner/native_application_support.h"
#include "mojo/util/filename_util.h"
#include "url/gurl.h"

using base::android::AttachCurrentThread;
using base::android::ScopedJavaLocalRef;
Expand All @@ -36,17 +34,15 @@ namespace {
void RunAndroidApplication(JNIEnv* env,
jobject j_context,
const base::FilePath& app_path,
jint j_handle,
bool is_cached_app) {
jint j_handle) {
InterfaceRequest<Application> application_request =
MakeRequest<Application>(MakeScopedHandle(MessagePipeHandle(j_handle)));

// Load the library, so that we can set the application context there if
// needed.
// TODO(vtl): We'd use a ScopedNativeLibrary, but it doesn't have .get()!
base::NativeLibrary app_library = LoadNativeApplication(
app_path, is_cached_app ? shell::NativeApplicationCleanup::DONT_DELETE
: shell::NativeApplicationCleanup::DELETE);
base::NativeLibrary app_library =
LoadNativeApplication(app_path, shell::NativeApplicationCleanup::DELETE);
if (!app_library)
return;

Expand All @@ -73,57 +69,6 @@ void RunAndroidApplication(JNIEnv* env,
base::UnloadNativeLibrary(app_library);
}

// Returns true if |url| denotes a cached app. If true |app_dir| is set to the
// path of the directory for the app and |path_to_mojo| the path of the app's
// .mojo file.
bool IsCachedApp(JNIEnv* env,
const GURL& url,
base::FilePath* app_dir,
base::FilePath* path_to_mojo) {
ScopedJavaLocalRef<jstring> j_local_apps_dir =
Java_AndroidHandler_getLocalAppsDir(env, GetApplicationContext());
const base::FilePath local_apps_fp(
ConvertJavaStringToUTF8(env, j_local_apps_dir.obj()));
const std::string local_apps(util::FilePathToFileURL(local_apps_fp).spec());
const std::string response_url(GURL(url).spec());
if (response_url.size() <= local_apps.size() ||
local_apps.compare(0u, local_apps.size(), response_url, 0u,
local_apps.size()) != 0) {
return false;
}

const std::string mojo_suffix(".mojo");
// app_rel_path is either something like html_viewer/html_viewer.mojo, or
// html_viewer.mojo, depending upon whether the app has a package.
const std::string app_rel_path(response_url.substr(local_apps.size() + 1));
const size_t slash_index = app_rel_path.find('/');
if (slash_index != std::string::npos) {
const std::string tail =
app_rel_path.substr(slash_index + 1, std::string::npos);
const std::string head = app_rel_path.substr(0, slash_index);
if (head.find('/') != std::string::npos ||
tail.size() <= mojo_suffix.size() ||
tail.compare(tail.size() - mojo_suffix.size(), tail.size(),
mojo_suffix) != 0) {
return false;
}
*app_dir = local_apps_fp.Append(head);
*path_to_mojo = app_dir->Append(tail);
return true;
}
if (app_rel_path.find('/') != std::string::npos ||
app_rel_path.size() <= mojo_suffix.size() ||
app_rel_path.compare(app_rel_path.size() - mojo_suffix.size(),
mojo_suffix.size(), mojo_suffix) != 0) {
return false;
}

*app_dir = local_apps_fp.Append(
app_rel_path.substr(0, app_rel_path.size() - mojo_suffix.size()));
*path_to_mojo = local_apps_fp.Append(app_rel_path);
return true;
}

} // namespace

AndroidHandler::AndroidHandler() : content_handler_factory_(this) {
Expand All @@ -136,30 +81,13 @@ void AndroidHandler::RunApplication(
InterfaceRequest<Application> application_request,
URLResponsePtr response) {
JNIEnv* env = AttachCurrentThread();
RunAndroidApplicationFn run_android_application_fn = &RunAndroidApplication;
if (!response->url.is_null()) {
base::FilePath internal_app_path;
base::FilePath path_to_mojo;
if (IsCachedApp(env, GURL(response->url), &internal_app_path,
&path_to_mojo)) {
ScopedJavaLocalRef<jstring> j_internal_app_path(
ConvertUTF8ToJavaString(env, internal_app_path.value()));
ScopedJavaLocalRef<jstring> j_path_to_mojo(
ConvertUTF8ToJavaString(env, path_to_mojo.value()));
Java_AndroidHandler_bootstrapCachedApp(
env, GetApplicationContext(), j_path_to_mojo.obj(),
j_internal_app_path.obj(),
application_request.PassMessagePipe().release().value(),
reinterpret_cast<jlong>(run_android_application_fn));
return;
}
}
ScopedJavaLocalRef<jstring> j_archive_path =
Java_AndroidHandler_getNewTempArchivePath(env, GetApplicationContext());
base::FilePath archive_path(
ConvertJavaStringToUTF8(env, j_archive_path.obj()));

common::BlockingCopyToFile(response->body.Pass(), archive_path);
RunAndroidApplicationFn run_android_application_fn = &RunAndroidApplication;
Java_AndroidHandler_bootstrap(
env, GetApplicationContext(), j_archive_path.obj(),
application_request.PassMessagePipe().release().value(),
Expand Down
169 changes: 23 additions & 146 deletions mojo/runner/android/apk/src/org/chromium/mojo/shell/AndroidHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
package org.chromium.mojo.shell;

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.base.Log;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Constructor;

Expand Down Expand Up @@ -46,10 +45,6 @@ public class AndroidHandler {
private static final String APP_DIRECTORY = "applications";
private static final String ASSET_DIRECTORY = "assets";

private static final String INTERNAL_DIRECTORY = "internal";

private enum AppType { CACHED, UNCACHED }

/**
* Deletes directories holding the temporary files. This should be called early on shell startup
* to clean up after the previous run.
Expand Down Expand Up @@ -82,158 +77,45 @@ private static String getNewTempArchivePath(Context context) throws IOException
@CalledByNative
private static boolean bootstrap(Context context, String archivePath, int handle,
long runApplicationPtr) {
File bootstrapJavaLibrary;
File bootstrapNativeLibrary;
File bootstrap_java_library;
File bootstrap_native_library;
try {
bootstrapJavaLibrary = FileHelper.extractFromAssets(context, BOOTSTRAP_JAVA_LIBRARY,
getAssetDir(context), FileHelper.FileType.TEMPORARY);
bootstrapNativeLibrary = FileHelper.extractFromAssets(context, BOOTSTRAP_NATIVE_LIBRARY,
getAssetDir(context), FileHelper.FileType.TEMPORARY);
bootstrap_java_library = FileHelper.extractFromAssets(context, BOOTSTRAP_JAVA_LIBRARY,
getAssetDir(context), true);
bootstrap_native_library = FileHelper.extractFromAssets(context,
BOOTSTRAP_NATIVE_LIBRARY, getAssetDir(context), true);
} catch (Exception e) {
Log.e(TAG, "Extraction of bootstrap files from assets failed.", e);
return false;
}

File applicationJavaLibrary;
File applicationNativeLibrary;
File application_java_library;
File application_native_library;
try {
File archive = new File(archivePath);
applicationJavaLibrary =
FileHelper.extractFromArchive(archive, JAVA_LIBRARY_SUFFIX, getAppDir(context),
FileHelper.FileType.TEMPORARY, FileHelper.ArchiveType.NORMAL);
applicationNativeLibrary = FileHelper.extractFromArchive(archive, NATIVE_LIBRARY_SUFFIX,
getAppDir(context), FileHelper.FileType.TEMPORARY,
FileHelper.ArchiveType.NORMAL);
application_java_library = FileHelper.extractFromArchive(archive, JAVA_LIBRARY_SUFFIX,
getAppDir(context));
application_native_library = FileHelper.extractFromArchive(archive,
NATIVE_LIBRARY_SUFFIX, getAppDir(context));
} catch (Exception e) {
Log.e(TAG, "Extraction of application files from the archive failed.", e);
return false;
}

return runApp(context, getDexOutputDir(context), applicationJavaLibrary,
applicationNativeLibrary, bootstrapJavaLibrary, bootstrapNativeLibrary, handle,
runApplicationPtr, AppType.UNCACHED);
}

private static File findFileInDirectoryMatchingSuffix(
File dir, final String suffix, final String ignore) {
File[] matchingFiles = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return !name.equals(ignore) && !name.equals(BOOTSTRAP_JAVA_LIBRARY)
&& !name.equals(BOOTSTRAP_NATIVE_LIBRARY) && name.endsWith(suffix);
}
});
return matchingFiles != null && matchingFiles.length == 1 ? matchingFiles[0] : null;
}

/**
* Extracts and runs a cached application.
*
* @param context the application context
* @param archivePath the path of the archive containing the application to be run
* @param appPathString path where the cached app's resources and other files are
* @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 bootstrapCachedApp(Context context, String archivePath,
String appPathString, int handle, long runApplicationPtr) {
final String appName = new File(appPathString).getName();
final File internalDir = new File(new File(appPathString), INTERNAL_DIRECTORY);
if (!internalDir.exists() && !internalDir.mkdirs()) {
Log.e(TAG, "Unable to create output dir " + internalDir.getAbsolutePath());
return false;
}
final File timestamp = FileHelper.prepareDirectoryForAssets(context, internalDir);
// We make the bootstrap library have a unique name on disk as otherwise we end up sharing
// bootstrap.so,
// which doesn't work.
// TODO(sky): figure out why android is caching the names.
final String bootstrapNativeLibraryName = appName + "-" + BOOTSTRAP_NATIVE_LIBRARY;
File bootstrapJavaLibrary = new File(internalDir, BOOTSTRAP_JAVA_LIBRARY);
File bootstrapNativeLibrary = new File(internalDir, bootstrapNativeLibraryName);
try {
// Use the files on disk if we have them, if not extract from the archive.
if (!bootstrapJavaLibrary.exists()) {
bootstrapJavaLibrary = FileHelper.extractFromAssets(context, BOOTSTRAP_JAVA_LIBRARY,
internalDir, FileHelper.FileType.PERMANENT);
}
if (!bootstrapNativeLibrary.exists()) {
final File extractedBootstrapNativeLibrary = FileHelper.extractFromAssets(context,
BOOTSTRAP_NATIVE_LIBRARY, internalDir, FileHelper.FileType.PERMANENT);
if (!extractedBootstrapNativeLibrary.renameTo(bootstrapNativeLibrary)) {
Log.e(TAG, "Unable to rename bootstrap library "
+ bootstrapNativeLibrary.getAbsolutePath());
return false;
}
}
} catch (Exception e) {
Log.e(TAG, "Extraction of bootstrap files from assets failed.", e);
return false;
}

// Because we allow the .so and .dex.jar to be anything we have to search in the internal
// directory for matching files.
// If we find one, we assume it's the one we want.
File applicationJavaLibrary =
findFileInDirectoryMatchingSuffix(internalDir, JAVA_LIBRARY_SUFFIX, "");
File applicationNativeLibrary = findFileInDirectoryMatchingSuffix(
internalDir, NATIVE_LIBRARY_SUFFIX, bootstrapNativeLibraryName);
try {
File archive = new File(archivePath);
if (applicationJavaLibrary == null) {
applicationJavaLibrary = FileHelper.extractFromArchive(archive, JAVA_LIBRARY_SUFFIX,
internalDir, FileHelper.FileType.PERMANENT,
FileHelper.ArchiveType.CONTENT_HANDLER);
}
if (applicationNativeLibrary == null) {
applicationNativeLibrary = FileHelper.extractFromArchive(archive,
NATIVE_LIBRARY_SUFFIX, internalDir, FileHelper.FileType.PERMANENT,
FileHelper.ArchiveType.CONTENT_HANDLER);
}
} catch (Exception e) {
Log.e(TAG, "Extraction of application files from the archive failed.", e);
return false;
}

FileHelper.createTimestampIfNecessary(timestamp);

return runApp(context, new File(internalDir, DEX_OUTPUT_DIRECTORY), applicationJavaLibrary,
applicationNativeLibrary, bootstrapJavaLibrary, bootstrapNativeLibrary, handle,
runApplicationPtr, AppType.CACHED);
}

/**
* Creates the class loader containing the bootstrap classes and runs it.
*
* @return true if successfully ran, false if encounteres some sort of error.
*/
private static boolean runApp(Context context, File dexOutputDir, File applicationJavaLibrary,
File applicationNativeLibrary, File bootstrapJavaLibrary, File bootstrapNativeLibrary,
int handle, long runApplicationPtr, AppType appType) {
final String dexPath = bootstrapJavaLibrary.getAbsolutePath() + File.pathSeparator
+ applicationJavaLibrary.getAbsolutePath();
if (!dexOutputDir.exists() && !dexOutputDir.mkdirs()) {
Log.e(TAG, "Unable to create dex output dir " + dexOutputDir.getAbsolutePath());
return false;
}
// TODO(sky): third arg is a path, but appears to have no effect, figure out if this relates
// to weird caching
// logic mentioned above.
DexClassLoader bootstrapLoader = new DexClassLoader(
dexPath, dexOutputDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
String dexPath = bootstrap_java_library.getAbsolutePath() + File.pathSeparator
+ application_java_library.getAbsolutePath();
DexClassLoader bootstrapLoader = new DexClassLoader(dexPath,
getDexOutputDir(context).getAbsolutePath(), null,
ClassLoader.getSystemClassLoader());

try {
Class<?> loadedClass = bootstrapLoader.loadClass(BOOTSTRAP_CLASS);
Class<? extends Runnable> bootstrapClass = loadedClass.asSubclass(Runnable.class);
Constructor<? extends Runnable> constructor =
bootstrapClass.getConstructor(Context.class, File.class, File.class,
Integer.class, Long.class, Boolean.class);
Runnable bootstrapRunnable = constructor.newInstance(context, bootstrapNativeLibrary,
applicationNativeLibrary, Integer.valueOf(handle),
Long.valueOf(runApplicationPtr), appType == AppType.CACHED);
Constructor<? extends Runnable> constructor = bootstrapClass.getConstructor(
Context.class, File.class, File.class, Integer.class, Long.class);
Runnable bootstrapRunnable = constructor.newInstance(context, bootstrap_native_library,
application_native_library, Integer.valueOf(handle),
Long.valueOf(runApplicationPtr));
bootstrapRunnable.run();
} catch (Throwable t) {
Log.e(TAG, "Running Bootstrap failed.", t);
Expand All @@ -242,11 +124,6 @@ private static boolean runApp(Context context, File dexOutputDir, File applicati
return true;
}

@CalledByNative
static String getLocalAppsDir(Context context) {
return ShellMain.getLocalAppsDir(context).getAbsolutePath();
}

private static File getDexOutputDir(Context context) {
return context.getDir(DEX_OUTPUT_DIRECTORY, Context.MODE_PRIVATE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,24 @@ public class Bootstrap implements Runnable {
private final File mApplicationNativeLibrary;
private final int mHandle;
private final long mRunApplicationPtr;
private final boolean mIsCachedApp;

public Bootstrap(Context context, File bootstrapNativeLibrary, File applicationNativeLibrary,
Integer handle, Long runApplicationPtr, Boolean isCachedApp) {
Integer handle, Long runApplicationPtr) {
mContext = context;
mBootstrapNativeLibrary = bootstrapNativeLibrary;
mApplicationNativeLibrary = applicationNativeLibrary;
mHandle = handle;
mRunApplicationPtr = runApplicationPtr;
mIsCachedApp = isCachedApp;
}

@Override
public void run() {
System.load(mBootstrapNativeLibrary.getAbsolutePath());
System.load(mApplicationNativeLibrary.getAbsolutePath());
nativeBootstrap(mContext, mApplicationNativeLibrary.getAbsolutePath(), mHandle,
mRunApplicationPtr, mIsCachedApp);
mRunApplicationPtr);
}

native void nativeBootstrap(Context context, String libraryPath, int handle,
long runApplicationPtr, boolean isCachedApp);
long runApplicationPtr);
}
Loading

0 comments on commit f8e1299

Please sign in to comment.