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 |