Index: base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java |
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 7dc015dc8f9ecb7c420e55046b2351646fb9fd2f..dbe25444d6349708e78ca61bf0a8132e481a30a3 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 |
@@ -5,7 +5,6 @@ |
package org.chromium.base.library_loader; |
import android.content.Context; |
-import android.content.pm.ApplicationInfo; |
import android.os.AsyncTask; |
import android.os.SystemClock; |
import android.util.Log; |
@@ -16,13 +15,6 @@ import org.chromium.base.JNINamespace; |
import org.chromium.base.TraceEvent; |
import org.chromium.base.VisibleForTesting; |
-import java.io.File; |
-import java.io.FileNotFoundException; |
-import java.io.IOException; |
-import java.io.RandomAccessFile; |
-import java.nio.MappedByteBuffer; |
-import java.nio.channels.FileChannel; |
-import java.util.HashMap; |
import java.util.Locale; |
import javax.annotation.Nullable; |
@@ -97,9 +89,6 @@ public class LibraryLoader { |
// final (like now) or be protected in some way (volatile of synchronized). |
private final int mLibraryProcessType; |
- // Library -> Path it has been loaded from. |
- private final HashMap<String, String> mLoadedFrom; |
- |
/** |
* @param libraryProcessType the process the shared library is loaded in. refer to |
* LibraryProcessType for possible values. |
@@ -119,7 +108,6 @@ public class LibraryLoader { |
private LibraryLoader(int libraryProcessType) { |
mLibraryProcessType = libraryProcessType; |
- mLoadedFrom = new HashMap<String, String>(); |
} |
/** |
@@ -204,43 +192,10 @@ public class LibraryLoader { |
} |
} |
- private void prefetchLibraryToMemory(Context context, String library) { |
- String libFilePath = mLoadedFrom.get(library); |
- if (libFilePath == null) { |
- Log.i(TAG, "File path not found for " + library); |
- return; |
- } |
- String apkFilePath = context.getApplicationInfo().sourceDir; |
- if (libFilePath.equals(apkFilePath)) { |
- // TODO(lizeb): Make pre-faulting work with libraries loaded from the APK. |
- return; |
- } |
- try { |
- TraceEvent.begin("LibraryLoader.prefetchLibraryToMemory"); |
- File file = new File(libFilePath); |
- int size = (int) file.length(); |
- FileChannel channel = new RandomAccessFile(file, "r").getChannel(); |
- MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size); |
- // TODO(lizeb): Figure out whether walking the entire library is really necessary. |
- // Page size is 4096 for all current Android architectures. |
- for (int index = 0; index < size; index += 4096) { |
- // Note: Testing shows that neither the Java compiler nor |
- // Dalvik/ART eliminates this loop. |
- buffer.get(index); |
- } |
- } catch (FileNotFoundException e) { |
- Log.w(TAG, "Library file not found: " + e); |
- } catch (IOException e) { |
- Log.w(TAG, "Impossible to map the file: " + e); |
- } finally { |
- TraceEvent.end("LibraryLoader.prefetchLibraryToMemory"); |
- } |
- } |
- |
/** Prefetches the native libraries in a background thread. |
* |
- * Launches an AsyncTask that maps the native libraries into memory, reads a |
- * part of each page from it, than unmaps it. This is done to warm up the |
+ * Launches an AsyncTask that, through a short-lived forked process, reads a |
+ * part of each page of the native library. This is done to warm up the |
* page cache, turning hard page faults into soft ones. |
* |
* This is done this way, as testing shows that fadvise(FADV_WILLNEED) is |
@@ -252,15 +207,12 @@ public class LibraryLoader { |
new AsyncTask<Void, Void, Void>() { |
@Override |
protected Void doInBackground(Void... params) { |
- // Note: AsyncTasks are executed in a low priority background |
- // thread, which is the desired behavior here since we don't |
- // want to interfere with the rest of the initialization. |
- for (String library : NativeLibraries.LIBRARIES) { |
- if (Linker.isChromiumLinkerLibrary(library)) { |
- continue; |
- } |
- prefetchLibraryToMemory(context, library); |
+ TraceEvent.begin("LibraryLoader.asyncPrefetchLibrariesToMemory"); |
+ if (!nativeForkAndPrefetchNativeLibrary()) { |
+ // TODO(lizeb): Add a UMA metric to estimate how often this happens. |
+ Log.w(TAG, "Forking a process to prefetch the native library failed."); |
} |
+ TraceEvent.end("LibraryLoader.asyncPrefetchLibrariesToMemory"); |
return null; |
} |
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
@@ -340,7 +292,6 @@ public class LibraryLoader { |
? "using no map executable support fallback" |
: "directly") |
+ " from within " + apkFilePath); |
- mLoadedFrom.put(library, apkFilePath); |
} else { |
// Unpack library fallback. |
Log.i(TAG, "Loading " + library |
@@ -350,19 +301,10 @@ public class LibraryLoader { |
context, library); |
fallbackWasUsed = true; |
Log.i(TAG, "Built fallback library " + libFilePath); |
- mLoadedFrom.put(library, libFilePath); |
} |
} else { |
// The library is in its own file. |
Log.i(TAG, "Loading " + library); |
- if (context != null) { |
- ApplicationInfo applicationInfo = context.getApplicationInfo(); |
- File file = new File(applicationInfo.nativeLibraryDir, libFilePath); |
- mLoadedFrom.put(library, file.getAbsolutePath()); |
- } else { |
- Log.i(TAG, "No context, cannot locate the native library file for " |
- + library); |
- } |
} |
// Load the library. |
@@ -580,4 +522,9 @@ 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 native String nativeGetVersionNumber(); |
+ |
+ // Finds the ranges corresponding to the native library pages, forks a new |
+ // process to prefetch these pages and waits for it. The new process then |
+ // terminates. This is blocking. |
+ private static native boolean nativeForkAndPrefetchNativeLibrary(); |
} |