diff options
author | feng@chromium.org <feng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-26 00:23:43 +0000 |
---|---|---|
committer | feng@chromium.org <feng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-26 00:23:43 +0000 |
commit | ffacd36b553bd0766c402acbc1905ac6825689d7 (patch) | |
tree | c92bb41b3342d72cc68b66d7a16f69de5beaa422 | |
parent | f60e7a4266ef813ed81b9d0c03150a07cecabd95 (diff) | |
download | chromium_src-ffacd36b553bd0766c402acbc1905ac6825689d7.zip chromium_src-ffacd36b553bd0766c402acbc1905ac6825689d7.tar.gz chromium_src-ffacd36b553bd0766c402acbc1905ac6825689d7.tar.bz2 |
Merge 258546 "[Android] Workaround of an android platform bug."
> [Android] Workaround of an android platform bug.
>
> On some Android devices (e.g., Sony Xperia), package manager may
> fail to extract native libraries when updating Chrome.
>
> The change tries alleviate the situation by:
> 1) name libchrome with version number;
> 2) when failed to load library, try to extract native libraies
> and load them.
>
> BUG=311644
>
> Review URL: https://codereview.chromium.org/200753002
TBR=feng@chromium.org
Review URL: https://codereview.chromium.org/211933004
git-svn-id: svn://svn.chromium.org/chrome/branches/1847/src@259415 0039d316-1c4b-4281-b951-d872f2087c98
16 files changed, 424 insertions, 15 deletions
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java index 6f6404a..5ce9c78 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java @@ -26,7 +26,7 @@ public abstract class AwBrowserProcess { public static void loadLibrary() { PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX); try { - LibraryLoader.loadNow(); + LibraryLoader.loadNow(null); } catch (ProcessInitException e) { throw new RuntimeException("Cannot load WebView", e); } diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java index 59bba30..149dc61 100644 --- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java +++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java @@ -4,6 +4,7 @@ package org.chromium.base.library_loader; +import android.content.Context; import android.util.Log; import org.chromium.base.CommandLine; @@ -40,6 +41,11 @@ public class LibraryLoader { // library_loader_hooks.cc). private static boolean sInitialized = false; + // One-way switch becomes true if the system library loading failed, + // and the right native library was found and loaded by the hack. + // The flag is used to report UMA stats later. + private static boolean sNativeLibraryHackWasUsed = false; + // TODO(cjhopman): Remove this once it's unused. /** * Doesn't do anything. @@ -49,15 +55,35 @@ public class LibraryLoader { } /** - * This method blocks until the library is fully loaded and initialized. + * TODO: http://crbug.com/354655 + * remove this method once WebViewChromiumFactoryProvider.java + * changes the call to ensureInitialized(null). */ public static void ensureInitialized() throws ProcessInitException { + ensureInitialized(null); + } + + /** + * This method blocks until the library is fully loaded and initialized. + * + * @param context The context in which the method is called, the caller + * may pass in a null context if it doesn't know in which context it + * is running, or it doesn't need to work around the issue + * http://b/13216167. + * + * When the context is not null and native library was not extracted + * by Android package manager, the LibraryLoader class + * will extract the native libraries from APK. This is a hack used to + * work around some Sony devices with the following platform bug: + * http://b/13216167. + */ + public static void ensureInitialized(Context context) throws ProcessInitException { synchronized (sLock) { if (sInitialized) { // Already initialized, nothing to do. return; } - loadAlreadyLocked(); + loadAlreadyLocked(context); initializeAlreadyLocked(CommandLine.getJavaSwitchesOrNull()); } } @@ -80,9 +106,9 @@ public class LibraryLoader { * * @throws ProcessInitException if the native library failed to load. */ - public static void loadNow() throws ProcessInitException { + public static void loadNow(Context context) throws ProcessInitException { synchronized (sLock) { - loadAlreadyLocked(); + loadAlreadyLocked(context); } } @@ -102,7 +128,7 @@ public class LibraryLoader { // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code - private static void loadAlreadyLocked() throws ProcessInitException { + private static void loadAlreadyLocked(Context context) throws ProcessInitException { try { if (!sLoaded) { assert !sInitialized; @@ -118,7 +144,21 @@ public class LibraryLoader { if (useChromiumLinker) Linker.loadLibrary(library); else - System.loadLibrary(library); + try { + System.loadLibrary(library); + if (context != null) { + LibraryLoaderHelper.deleteWorkaroundLibrariesAsynchronously( + context); + } + } catch (UnsatisfiedLinkError e) { + if (context != null + && LibraryLoaderHelper.tryLoadLibraryUsingWorkaround(context, + library)) { + sNativeLibraryHackWasUsed = true; + } else { + throw e; + } + } } if (useChromiumLinker) Linker.finishLibraryLoad(); @@ -165,6 +205,8 @@ public class LibraryLoader { if (Linker.isUsed()) nativeRecordChromiumAndroidLinkerHistogram(Linker.loadAtFixedAddressFailed(), SysUtils.isLowEndDevice()); + + nativeRecordNativeLibraryHack(sNativeLibraryHackWasUsed); } // Only methods needed before or during normal JNI registration are during System.OnLoad. @@ -185,4 +227,6 @@ public class LibraryLoader { // Get the version of the native library. This is needed so that we can check we // have the right version before initializing the (rest of the) JNI. private static native String nativeGetVersionNumber(); + + private static native void nativeRecordNativeLibraryHack(boolean usedHack); } diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java new file mode 100644 index 0000000..7eeb2c8 --- /dev/null +++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java @@ -0,0 +1,259 @@ +// Copyright 2014 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.base.library_loader; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.os.Build; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * The class provides helper functions to extract native libraries from APK, + * and load libraries from there. + * + * The class should be package-visible only, but made public for testing + * purpose. + */ +public class LibraryLoaderHelper { + private static final String TAG = "LibraryLoaderHelper"; + + private static final String LIB_DIR = "lib"; + + /** + * One-way switch becomes true if native libraries were unpacked + * from APK. + */ + private static boolean sLibrariesWereUnpacked = false; + + /** + * Loads native libraries using workaround only, skip the library in system + * lib path. The method exists only for testing purpose. + * Caller must ensure thread safety of this method. + * @param context + */ + public static boolean loadNativeLibrariesUsingWorkaroundForTesting(Context context) { + // Although tryLoadLibraryUsingWorkaround might be called multiple times, + // libraries should only be unpacked once, this is guaranteed by + // sLibrariesWereUnpacked. + for (String library : NativeLibraries.LIBRARIES) { + if (!tryLoadLibraryUsingWorkaround(context, library)) { + return false; + } + } + return true; + } + + /** + * Try to load a native library using a workaround of + * http://b/13216167. + * + * Workaround for b/13216167 was adapted from code in + * https://googleplex-android-review.git.corp.google.com/#/c/433061 + * + * More details about http://b/13216167: + * PackageManager may fail to update shared library. + * + * Native library directory in an updated package is a symbolic link + * to a directory in /data/app-lib/<package name>, for example: + * /data/data/com.android.chrome/lib -> /data/app-lib/com.android.chrome[-1]. + * When updating the application, the PackageManager create a new directory, + * e.g., /data/app-lib/com.android.chrome-2, and remove the old symlink and + * recreate one to the new directory. However, on some devices (e.g. Sony Xperia), + * the symlink was updated, but fails to extract new native libraries from + * the new apk. + + * We make the following changes to alleviate the issue: + * 1) name the native library with apk version code, e.g., + * libchrome.1750.136.so, 1750.136 is Chrome version number; + * 2) first try to load the library using System.loadLibrary, + * if that failed due to the library file was not found, + * search the named library in a /data/data/com.android.chrome/app_lib + * directory. Because of change 1), each version has a different native + * library name, so avoid mistakenly using the old native library. + * + * If named library is not in /data/data/com.android.chrome/app_lib directory, + * extract native libraries from apk and cache in the directory. + * + * This function doesn't throw UnsatisfiedLinkError, the caller needs to + * check the return value. + */ + static boolean tryLoadLibraryUsingWorkaround(Context context, String library) { + assert context != null; + File libFile = getWorkaroundLibFile(context, library); + if (!libFile.exists() && !unpackLibrariesOnce(context)) { + return false; + } + try { + System.load(libFile.getAbsolutePath()); + return true; + } catch (UnsatisfiedLinkError e) { + return false; + } + } + + /** + * Returns the directory for holding extracted native libraries. + * It may create the directory if it doesn't exist. + * + * @param context + * @return the directory file object + */ + public static File getWorkaroundLibDir(Context context) { + return context.getDir(LIB_DIR, Context.MODE_PRIVATE); + } + + private static File getWorkaroundLibFile(Context context, String library) { + String libName = System.mapLibraryName(library); + return new File(getWorkaroundLibDir(context), libName); + } + + /** + * Unpack native libraries from the APK file. The method is supposed to + * be called only once. It deletes existing files in unpacked directory + * before unpacking. + * + * @param context + * @return true when unpacking was successful, false when failed or called + * more than once. + */ + private static boolean unpackLibrariesOnce(Context context) { + if (sLibrariesWereUnpacked) { + return false; + } + sLibrariesWereUnpacked = true; + + File libDir = getWorkaroundLibDir(context); + if (libDir.exists()) { + assert libDir.isDirectory(); + deleteDirectorySync(libDir); + } + + try { + ApplicationInfo appInfo = context.getApplicationInfo(); + ZipFile file = new ZipFile(new File(appInfo.sourceDir), ZipFile.OPEN_READ); + for (String libName : NativeLibraries.LIBRARIES) { + String jniNameInApk = "lib/" + Build.CPU_ABI + "/" + + System.mapLibraryName(libName); + + final ZipEntry entry = file.getEntry(jniNameInApk); + if (entry == null) { + Log.e(TAG, appInfo.sourceDir + " doesn't have file " + jniNameInApk); + file.close(); + deleteDirectorySync(libDir); + return false; + } + + File outputFile = getWorkaroundLibFile(context, libName); + + Log.i(TAG, "Extracting native libraries into " + outputFile.getAbsolutePath()); + + assert !outputFile.exists(); + + try { + if (!outputFile.createNewFile()) { + throw new IOException(); + } + + InputStream is = null; + FileOutputStream os = null; + try { + is = file.getInputStream(entry); + os = new FileOutputStream(outputFile); + int count = 0; + byte[] buffer = new byte[16 * 1024]; + while ((count = is.read(buffer)) > 0) { + os.write(buffer, 0, count); + } + } finally { + try { + if (is != null) is.close(); + } finally { + if (os != null) os.close(); + } + } + // Change permission to rwxr-xr-x + outputFile.setReadable(true, false); + outputFile.setExecutable(true, false); + outputFile.setWritable(true); + } catch (IOException e) { + if (outputFile.exists()) { + if (!outputFile.delete()) { + Log.e(TAG, "Failed to delete " + outputFile.getAbsolutePath()); + } + } + file.close(); + throw e; + } + } + file.close(); + return true; + } catch (IOException e) { + Log.e(TAG, "Failed to unpack native libraries", e); + deleteDirectorySync(libDir); + return false; + } + } + + /** + * Delete old library files in the backup directory. + * The actual deletion is done in a background thread. + * + * @param context + */ + static void deleteWorkaroundLibrariesAsynchronously(Context context) { + // Child process should not reach here. + final File libDir = getWorkaroundLibDir(context); + if (libDir.exists()) { + assert libDir.isDirectory(); + // Async deletion + new Thread() { + @Override + public void run() { + deleteDirectorySync(libDir); + } + }.start(); + } + } + + /** + * Delete the workaround libraries and directory synchronously. + * For testing purpose only. + * @param context + */ + public static void deleteWorkaroundLibrariesSynchronously(Context context) { + File libDir = getWorkaroundLibDir(context); + if (libDir.exists()) { + deleteDirectorySync(libDir); + } + } + + private static void deleteDirectorySync(File dir) { + try { + File[] files = dir.listFiles(); + if (files != null) { + for (File file : files) { + String fileName = file.getName(); + if (!file.delete()) { + Log.e(TAG, "Failed to remove " + file.getAbsolutePath()); + } + } + } + if (!dir.delete()) { + Log.w(TAG, "Failed to remove " + dir.getAbsolutePath()); + } + return; + } catch (Exception e) { + Log.e(TAG, "Failed to remove old libs, ", e); + } + } +} diff --git a/base/android/javatests/src/org/chromium/base/LibraryLoaderHelperTest.java b/base/android/javatests/src/org/chromium/base/LibraryLoaderHelperTest.java new file mode 100644 index 0000000..85f4c77 --- /dev/null +++ b/base/android/javatests/src/org/chromium/base/LibraryLoaderHelperTest.java @@ -0,0 +1,53 @@ +// Copyright 2014 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.base; + +import android.content.Context; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +import org.chromium.base.library_loader.LibraryLoaderHelper; + +import java.io.File; + +/** + * Test class for the native library hack. + */ +public class LibraryLoaderHelperTest extends InstrumentationTestCase { + private static final String TAG = "LibraryLoaderHelperTest"; + + @Override + public void setUp() throws Exception { + Context context = getInstrumentation().getTargetContext(); + LibraryLoaderHelper.deleteWorkaroundLibrariesSynchronously(context); + } + + @MediumTest + public void testLoadNativeLibraries() { + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + Context context = getInstrumentation().getTargetContext(); + File libDir = LibraryLoaderHelper.getWorkaroundLibDir(context); + assertTrue(libDir.exists()); + assertTrue(libDir.isDirectory()); + assertEquals(libDir.list().length, 0); + + assertTrue( + LibraryLoaderHelper.loadNativeLibrariesUsingWorkaroundForTesting( + context)); + + assertTrue(libDir.list().length > 0); + } + }); + } + + @Override + public void tearDown() throws Exception { + Context context = getInstrumentation().getTargetContext(); + LibraryLoaderHelper.deleteWorkaroundLibrariesSynchronously(context); + super.tearDown(); + } +} diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc index 8fa16df..0145eab 100644 --- a/base/android/library_loader/library_loader_hooks.cc +++ b/base/android/library_loader/library_loader_hooks.cc @@ -64,5 +64,9 @@ jstring GetVersionNumber(JNIEnv* env, jclass clazz) { return env->NewStringUTF(g_library_version_number); } +static void RecordNativeLibraryHack(JNIEnv*, jclass, jboolean usedHack) { + UMA_HISTOGRAM_BOOLEAN("LibraryLoader.NativeLibraryHack", usedHack); +} + } // namespace android } // namespace base diff --git a/build/android/gyp/delete_files.py b/build/android/gyp/delete_files.py new file mode 100755 index 0000000..802824d --- /dev/null +++ b/build/android/gyp/delete_files.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# Copyright 2014 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. + +"""Delete files in directories matching a pattern. +""" + +import glob +import optparse +import os +import sys + +def main(): + parser = optparse.OptionParser() + parser.add_option( + '--pattern', + help='Pattern for matching Files to delete.') + parser.add_option( + '--keep', + help='Files to keep even if they matches the pattern.') + + options, args = parser.parse_args() + + if not options.pattern or not args: + print 'No --pattern or target directories given' + return + + for target_dir in args: + target_pattern = os.path.join(target_dir, options.pattern) + matching_files = glob.glob(target_pattern) + + keep_pattern = os.path.join(target_dir, options.keep) + files_to_keep = glob.glob(keep_pattern) + + for target_file in matching_files: + if target_file in files_to_keep: + continue + + if os.path.isfile(target_file): + os.remove(target_file) + +if __name__ == '__main__': + sys.exit(main()) + diff --git a/build/common.gypi b/build/common.gypi index 0050cc5..d34720b 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -2019,6 +2019,8 @@ # processing. 'chromium_code%': '<(chromium_code)', + 'component%': '<(component)', + # See http://msdn.microsoft.com/en-us/library/aa652360(VS.71).aspx 'win_release_Optimization%': '2', # 2 = /Os 'win_debug_Optimization%': '0', # 0 = /Od diff --git a/chrome/version.gypi b/chrome/version.gypi index f1af6fdc..7619e6f 100644 --- a/chrome/version.gypi +++ b/chrome/version.gypi @@ -12,6 +12,8 @@ 'version_path': '<(version_path)', 'version_full': '<!(python <(version_py_path) -f <(version_path) -t "@MAJOR@.@MINOR@.@BUILD@.@PATCH@")', + 'version_libchrome_short': + '<!(python <(version_py_path) -f <(version_path) -t "@BUILD@.@PATCH@")', 'version_mac_dylib': '<!(python <(version_py_path) -f <(version_path) -t "@BUILD@.@PATCH_HI@.@PATCH_LO@" -e "PATCH_HI=int(PATCH)/256" -e "PATCH_LO=int(PATCH)%256")', }, # variables diff --git a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java index 769249e..4fec772 100644 --- a/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java +++ b/content/public/android/java/src/org/chromium/content/app/ChildProcessService.java @@ -141,7 +141,7 @@ public class ChildProcessService extends Service { } } try { - LibraryLoader.loadNow(); + LibraryLoader.loadNow(getApplicationContext()); } catch (ProcessInitException e) { Log.e(TAG, "Failed to load native library, exiting child process", e); System.exit(-1); diff --git a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java index caad20c..4bc70d3 100644 --- a/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java +++ b/content/public/android/java/src/org/chromium/content/browser/BrowserStartupController.java @@ -271,7 +271,7 @@ public class BrowserStartupController { // Normally Main.java will have already loaded the library asynchronously, we only need // to load it here if we arrived via another flow, e.g. bookmark access & sync setup. - LibraryLoader.ensureInitialized(); + LibraryLoader.ensureInitialized(mContext); // TODO(yfriedman): Remove dependency on a command line flag for this. DeviceUtils.addDeviceSpecificUserAgentSwitch(mContext); diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentCommandLineTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentCommandLineTest.java index a0a3d4e..3bb1ee4 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ContentCommandLineTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentCommandLineTest.java @@ -47,7 +47,7 @@ public class ContentCommandLineTest extends InstrumentationTestCase { public void run() { ContentShellApplication.initializeApplicationParameters(); try { - LibraryLoader.ensureInitialized(); + LibraryLoader.ensureInitialized(null); } catch (ProcessInitException e) { throw new Error(e); } diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java index 66c17e0f..5ff9949 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ImportantFileWriterAndroidTest.java @@ -34,7 +34,7 @@ public class ImportantFileWriterAndroidTest extends InstrumentationTestCase { public void run() { ContentShellApplication.initializeApplicationParameters(); try { - LibraryLoader.ensureInitialized(); + LibraryLoader.ensureInitialized(null); } catch (ProcessInitException e) { throw new Error(e); } diff --git a/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsActivity.java b/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsActivity.java index f00dfd1..987a6d2 100644 --- a/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsActivity.java +++ b/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsActivity.java @@ -34,7 +34,7 @@ public class ContentBrowserTestsActivity extends Activity { super.onCreate(savedInstanceState); try { - LibraryLoader.ensureInitialized(); + LibraryLoader.ensureInitialized(null); } catch (ProcessInitException e) { Log.i(TAG, "Cannot load content_browsertests:" + e); System.exit(-1); diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java index b3bca6b..91dc5f3 100644 --- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java +++ b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestActivity.java @@ -85,7 +85,7 @@ public class ChromiumLinkerTestActivity extends Activity { // Load the library in the browser process, this will also run the test // runner in this process. try { - LibraryLoader.ensureInitialized(); + LibraryLoader.ensureInitialized(null); } catch (ProcessInitException e) { Log.i(TAG, "Cannot load chromium_linker_test:" + e); } diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java index 0e5aa74..287588f 100644 --- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java +++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java @@ -60,7 +60,7 @@ public class ContentShellActivity extends Activity { DeviceUtils.addDeviceSpecificUserAgentSwitch(this); try { - LibraryLoader.ensureInitialized(); + LibraryLoader.ensureInitialized(null); } catch (ProcessInitException e) { Log.e(TAG, "ContentView initialization failed.", e); // Since the library failed to initialize nothing in the application diff --git a/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellActivity.java b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellActivity.java index 15a5861..c697f5e 100644 --- a/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellActivity.java +++ b/mojo/shell/android/apk/src/org/chromium/mojo_shell_apk/MojoShellActivity.java @@ -26,7 +26,7 @@ public class MojoShellActivity extends Activity { super.onCreate(savedInstanceState); try { - LibraryLoader.ensureInitialized(); + LibraryLoader.ensureInitialized(null); } catch (ProcessInitException e) { Log.e(TAG, "libmojo_shell initialization failed.", e); finish(); |