| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.base.library_loader; | 5 package org.chromium.base.library_loader; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.os.SystemClock; | 8 import android.os.SystemClock; |
| 9 import android.util.Log; | 9 import android.util.Log; |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 * primitives are used to ensure that overlapping requests from different | 23 * primitives are used to ensure that overlapping requests from different |
| 24 * threads are handled sequentially. | 24 * threads are handled sequentially. |
| 25 * | 25 * |
| 26 * See also base/android/library_loader/library_loader_hooks.cc, which contains | 26 * See also base/android/library_loader/library_loader_hooks.cc, which contains |
| 27 * the native counterpart to this class. | 27 * the native counterpart to this class. |
| 28 */ | 28 */ |
| 29 @JNINamespace("base::android") | 29 @JNINamespace("base::android") |
| 30 public class LibraryLoader { | 30 public class LibraryLoader { |
| 31 private static final String TAG = "LibraryLoader"; | 31 private static final String TAG = "LibraryLoader"; |
| 32 | 32 |
| 33 // Set to true to enable debug logs. |
| 34 private static final boolean DEBUG = false; |
| 35 |
| 33 // Guards all access to the libraries | 36 // Guards all access to the libraries |
| 34 private static final Object sLock = new Object(); | 37 private static final Object sLock = new Object(); |
| 35 | 38 |
| 36 // One-way switch becomes true when the libraries are loaded. | 39 // One-way switch becomes true when the libraries are loaded. |
| 37 private static boolean sLoaded = false; | 40 private static boolean sLoaded = false; |
| 38 | 41 |
| 39 // One-way switch becomes true when the Java command line is switched to | 42 // One-way switch becomes true when the Java command line is switched to |
| 40 // native. | 43 // native. |
| 41 private static boolean sCommandLineSwitched = false; | 44 private static boolean sCommandLineSwitched = false; |
| 42 | 45 |
| 43 // One-way switch becomes true when the libraries are initialized ( | 46 // One-way switch becomes true when the libraries are initialized ( |
| 44 // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in | 47 // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in |
| 45 // library_loader_hooks.cc). | 48 // library_loader_hooks.cc). |
| 46 private static boolean sInitialized = false; | 49 private static boolean sInitialized = false; |
| 47 | 50 |
| 48 // One-way switches recording attempts to use Relro sharing in the browser. | 51 // One-way switches recording attempts to use Relro sharing in the browser. |
| 49 // The flags are used to report UMA stats later. | 52 // The flags are used to report UMA stats later. |
| 50 private static boolean sIsUsingBrowserSharedRelros = false; | 53 private static boolean sIsUsingBrowserSharedRelros = false; |
| 51 private static boolean sLoadAtFixedAddressFailed = false; | 54 private static boolean sLoadAtFixedAddressFailed = false; |
| 52 | 55 |
| 53 // One-way switch becomes true if the library was loaded from the APK file | 56 // One-way switch becomes true if the library was loaded from the APK file |
| 54 // directly. | 57 // directly. |
| 55 private static boolean sLibraryWasLoadedFromApk = false; | 58 private static boolean sLibraryWasLoadedFromApk = false; |
| 56 | 59 |
| 60 // One-way switch becomes false if the Chromium library should be loaded |
| 61 // directly from the APK file but it was not aligned. |
| 62 private static boolean sLibraryWasAlignedInApk = true; |
| 63 |
| 57 // One-way switch becomes true if the system library loading failed, | 64 // One-way switch becomes true if the system library loading failed, |
| 58 // and the right native library was found and loaded by the hack. | 65 // and the right native library was found and loaded by the hack. |
| 59 // The flag is used to report UMA stats later. | 66 // The flag is used to report UMA stats later. |
| 60 private static boolean sNativeLibraryHackWasUsed = false; | 67 private static boolean sNativeLibraryHackWasUsed = false; |
| 61 | 68 |
| 62 /** | 69 /** |
| 63 * The same as ensureInitialized(null, false), should only be called | 70 * The same as ensureInitialized(null, false), should only be called |
| 64 * by non-browser processes. | 71 * by non-browser processes. |
| 65 * | 72 * |
| 66 * @throws ProcessInitException | 73 * @throws ProcessInitException |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 158 assert !sInitialized; | 165 assert !sInitialized; |
| 159 | 166 |
| 160 long startTime = SystemClock.uptimeMillis(); | 167 long startTime = SystemClock.uptimeMillis(); |
| 161 boolean useChromiumLinker = Linker.isUsed(); | 168 boolean useChromiumLinker = Linker.isUsed(); |
| 162 | 169 |
| 163 if (useChromiumLinker) { | 170 if (useChromiumLinker) { |
| 164 // Load libraries using the Chromium linker. | 171 // Load libraries using the Chromium linker. |
| 165 Linker.prepareLibraryLoad(); | 172 Linker.prepareLibraryLoad(); |
| 166 | 173 |
| 167 for (String library : NativeLibraries.LIBRARIES) { | 174 for (String library : NativeLibraries.LIBRARIES) { |
| 175 // Don't self-load the linker. This is because the build
system is |
| 176 // not clever enough to understand that all the librarie
s packaged |
| 177 // in the final .apk don't need to be explicitly loaded. |
| 178 if (Linker.isChromiumLinkerLibrary(library)) { |
| 179 if (DEBUG) Log.i(TAG, "ignoring self-linker load"); |
| 180 continue; |
| 181 } |
| 182 |
| 168 String zipfile = null; | 183 String zipfile = null; |
| 169 if (Linker.isInZipFile()) { | 184 if (Linker.isInZipFile()) { |
| 170 zipfile = context.getApplicationInfo().sourceDir; | 185 zipfile = context.getApplicationInfo().sourceDir; |
| 186 sLibraryWasAlignedInApk = Linker.checkLibraryAligned
InApk( |
| 187 zipfile, System.mapLibraryName(library)); |
| 171 Log.i(TAG, "Loading " + library + " from within " +
zipfile); | 188 Log.i(TAG, "Loading " + library + " from within " +
zipfile); |
| 172 } else { | 189 } else { |
| 173 Log.i(TAG, "Loading: " + library); | 190 Log.i(TAG, "Loading: " + library); |
| 174 } | 191 } |
| 175 | 192 |
| 176 boolean isLoaded = false; | 193 boolean isLoaded = false; |
| 177 if (Linker.isUsingBrowserSharedRelros()) { | 194 if (Linker.isUsingBrowserSharedRelros()) { |
| 178 sIsUsingBrowserSharedRelros = true; | 195 sIsUsingBrowserSharedRelros = true; |
| 179 try { | 196 try { |
| 180 if (zipfile != null) { | 197 if (zipfile != null) { |
| 181 Linker.loadLibraryInZipFile(zipfile, library
); | 198 Linker.loadLibraryInZipFile(zipfile, library
); |
| 182 sLibraryWasLoadedFromApk = true; | 199 sLibraryWasLoadedFromApk = true; |
| 183 } else { | 200 } else { |
| 184 Linker.loadLibrary(library); | 201 Linker.loadLibrary(library); |
| 185 } | 202 } |
| 186 isLoaded = true; | 203 isLoaded = true; |
| 187 } catch (UnsatisfiedLinkError e) { | 204 } catch (UnsatisfiedLinkError e) { |
| 188 Log.w(TAG, "Failed to load native library with s
hared RELRO, " + | 205 Log.w(TAG, "Failed to load native library with s
hared RELRO, " |
| 189 "retrying without"); | 206 + "retrying without"); |
| 190 Linker.disableSharedRelros(); | 207 Linker.disableSharedRelros(); |
| 191 sLoadAtFixedAddressFailed = true; | 208 sLoadAtFixedAddressFailed = true; |
| 192 } | 209 } |
| 193 } | 210 } |
| 194 if (!isLoaded) { | 211 if (!isLoaded) { |
| 195 if (zipfile != null) { | 212 if (zipfile != null) { |
| 196 Linker.loadLibraryInZipFile(zipfile, library); | 213 Linker.loadLibraryInZipFile(zipfile, library); |
| 197 sLibraryWasLoadedFromApk = true; | 214 sLibraryWasLoadedFromApk = true; |
| 198 } else { | 215 } else { |
| 199 Linker.loadLibrary(library); | 216 Linker.loadLibrary(library); |
| 200 } | 217 } |
| 201 } | 218 } |
| 202 } | 219 } |
| 203 | 220 |
| 204 Linker.finishLibraryLoad(); | 221 Linker.finishLibraryLoad(); |
| 205 } else { | 222 } else { |
| 206 // Load libraries using the system linker. | 223 // Load libraries using the system linker. |
| 207 for (String library : NativeLibraries.LIBRARIES) { | 224 for (String library : NativeLibraries.LIBRARIES) { |
| 208 try { | 225 try { |
| 209 System.loadLibrary(library); | 226 System.loadLibrary(library); |
| 210 } catch (UnsatisfiedLinkError e) { | 227 } catch (UnsatisfiedLinkError e) { |
| 211 if (context != null | 228 if (context != null |
| 212 && LibraryLoaderHelper.tryLoadLibraryUsingWorkar
ound(context, | 229 && LibraryLoaderHelper.tryLoadLibraryUsingWo
rkaround(context, |
| 213
library)) { | 230
library)) { |
| 214 sNativeLibraryHackWasUsed = true; | 231 sNativeLibraryHackWasUsed = true; |
| 215 } else { | 232 } else { |
| 216 throw e; | 233 throw e; |
| 217 } | 234 } |
| 218 } | 235 } |
| 219 } | 236 } |
| 220 } | 237 } |
| 221 | 238 |
| 222 if (context != null | 239 if (context != null |
| 223 && shouldDeleteOldWorkaroundLibraries | 240 && shouldDeleteOldWorkaroundLibraries |
| 224 && !sNativeLibraryHackWasUsed) { | 241 && !sNativeLibraryHackWasUsed) { |
| 225 LibraryLoaderHelper.deleteWorkaroundLibrariesAsynchronously( | 242 LibraryLoaderHelper.deleteWorkaroundLibrariesAsynchronously( |
| 226 context); | 243 context); |
| 227 } | 244 } |
| 228 | 245 |
| 229 long stopTime = SystemClock.uptimeMillis(); | 246 long stopTime = SystemClock.uptimeMillis(); |
| 230 Log.i(TAG, String.format("Time to load native libraries: %d ms (
timestamps %d-%d)", | 247 Log.i(TAG, String.format("Time to load native libraries: %d ms (
timestamps %d-%d)", |
| 231 stopTime - startTime, | 248 stopTime - startTime, |
| 232 startTime % 10000, | 249 startTime % 10000, |
| 233 stopTime % 10000)); | 250 stopTime % 10000)); |
| 234 | 251 |
| 235 sLoaded = true; | 252 sLoaded = true; |
| 236 } | 253 } |
| 237 } catch (UnsatisfiedLinkError e) { | 254 } catch (UnsatisfiedLinkError e) { |
| 238 throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBR
ARY_LOAD_FAILED, e); | 255 throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBR
ARY_LOAD_FAILED, e); |
| 239 } | 256 } |
| 240 // Check that the version of the library we have loaded matches the vers
ion we expect | 257 // Check that the version of the library we have loaded matches the vers
ion we expect |
| 241 Log.i(TAG, String.format( | 258 Log.i(TAG, String.format( |
| 242 "Expected native library version number \"%s\"," + | 259 "Expected native library version number \"%s\"," |
| 243 "actual native library version number \"%s\"", | 260 + "actual native library version number \"%s\"", |
| 244 NativeLibraries.sVersionNumber, | 261 NativeLibraries.sVersionNumber, |
| 245 nativeGetVersionNumber())); | 262 nativeGetVersionNumber())); |
| 246 if (!NativeLibraries.sVersionNumber.equals(nativeGetVersionNumber())) { | 263 if (!NativeLibraries.sVersionNumber.equals(nativeGetVersionNumber())) { |
| 247 throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBR
ARY_WRONG_VERSION); | 264 throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBR
ARY_WRONG_VERSION); |
| 248 } | 265 } |
| 249 } | 266 } |
| 250 | 267 |
| 251 // The WebView requires the Command Line to be switched over before | 268 // The WebView requires the Command Line to be switched over before |
| 252 // initialization is done. This is okay in the WebView's case since the | 269 // initialization is done. This is okay in the WebView's case since the |
| 253 // JNI is already loaded by this point. | 270 // JNI is already loaded by this point. |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 | 336 |
| 320 // Returns the device's status for loading a library directly from the APK f
ile. | 337 // Returns the device's status for loading a library directly from the APK f
ile. |
| 321 // This method can only be called when the Chromium linker is used. | 338 // This method can only be called when the Chromium linker is used. |
| 322 private static int getLibraryLoadFromApkStatus(Context context) { | 339 private static int getLibraryLoadFromApkStatus(Context context) { |
| 323 assert Linker.isUsed(); | 340 assert Linker.isUsed(); |
| 324 | 341 |
| 325 if (sLibraryWasLoadedFromApk) { | 342 if (sLibraryWasLoadedFromApk) { |
| 326 return LibraryLoadFromApkStatusCodes.SUCCESSFUL; | 343 return LibraryLoadFromApkStatusCodes.SUCCESSFUL; |
| 327 } | 344 } |
| 328 | 345 |
| 346 if (!sLibraryWasAlignedInApk) { |
| 347 return LibraryLoadFromApkStatusCodes.NOT_ALIGNED; |
| 348 } |
| 349 |
| 329 if (context == null) { | 350 if (context == null) { |
| 330 Log.w(TAG, "Unknown APK filename due to null context"); | 351 Log.w(TAG, "Unknown APK filename due to null context"); |
| 331 return LibraryLoadFromApkStatusCodes.UNKNOWN; | 352 return LibraryLoadFromApkStatusCodes.UNKNOWN; |
| 332 } | 353 } |
| 333 | 354 |
| 334 return Linker.checkLibraryLoadFromApkSupport(context.getApplicationInfo(
).sourceDir) ? | 355 return Linker.checkLibraryLoadFromApkSupport(context.getApplicationInfo(
).sourceDir) |
| 335 LibraryLoadFromApkStatusCodes.SUPPORTED : | 356 ? LibraryLoadFromApkStatusCodes.SUPPORTED |
| 336 LibraryLoadFromApkStatusCodes.NOT_SUPPORTED; | 357 : LibraryLoadFromApkStatusCodes.NOT_SUPPORTED; |
| 337 } | 358 } |
| 338 | 359 |
| 339 // Register pending Chromium linker histogram state for renderer processes.
This cannot be | 360 // Register pending Chromium linker histogram state for renderer processes.
This cannot be |
| 340 // recorded as a histogram immediately because histograms and IPC are not re
ady at the | 361 // recorded as a histogram immediately because histograms and IPC are not re
ady at the |
| 341 // time it are captured. This function stores a pending value, so that a lat
er call to | 362 // time it are captured. This function stores a pending value, so that a lat
er call to |
| 342 // RecordChromiumAndroidLinkerRendererHistogram() will record it correctly. | 363 // RecordChromiumAndroidLinkerRendererHistogram() will record it correctly. |
| 343 public static void registerRendererProcessHistogram(boolean requestedSharedR
elro, | 364 public static void registerRendererProcessHistogram(boolean requestedSharedR
elro, |
| 344 boolean loadAtFixedAddre
ssFailed) { | 365 boolean loadAtFixedAddre
ssFailed) { |
| 345 if (Linker.isUsed()) { | 366 if (Linker.isUsed()) { |
| 346 nativeRegisterChromiumAndroidLinkerRendererHistogram(requestedShared
Relro, | 367 nativeRegisterChromiumAndroidLinkerRendererHistogram(requestedShared
Relro, |
| (...skipping 26 matching lines...) Expand all Loading... |
| 373 private static native void nativeRegisterChromiumAndroidLinkerRendererHistog
ram( | 394 private static native void nativeRegisterChromiumAndroidLinkerRendererHistog
ram( |
| 374 boolean requestedSharedRelro, | 395 boolean requestedSharedRelro, |
| 375 boolean loadAtFixedAddressFailed); | 396 boolean loadAtFixedAddressFailed); |
| 376 | 397 |
| 377 // Get the version of the native library. This is needed so that we can chec
k we | 398 // Get the version of the native library. This is needed so that we can chec
k we |
| 378 // have the right version before initializing the (rest of the) JNI. | 399 // have the right version before initializing the (rest of the) JNI. |
| 379 private static native String nativeGetVersionNumber(); | 400 private static native String nativeGetVersionNumber(); |
| 380 | 401 |
| 381 private static native void nativeRecordNativeLibraryHack(boolean usedHack); | 402 private static native void nativeRecordNativeLibraryHack(boolean usedHack); |
| 382 } | 403 } |
| OLD | NEW |