Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(312)

Side by Side Diff: base/android/java/src/org/chromium/base/library_loader/Linker.java

Issue 1641513004: Update //base to chromium 9659b08ea5a34f889dc4166217f438095ddc10d2 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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.os.Bundle; 7 import android.os.Bundle;
8 import android.os.Parcel; 8 import android.os.Parcel;
9 import android.os.ParcelFileDescriptor; 9 import android.os.ParcelFileDescriptor;
10 import android.os.Parcelable; 10 import android.os.Parcelable;
11 import android.util.Log;
12 11
13 import org.chromium.base.CalledByNative; 12 import org.chromium.base.Log;
14 import org.chromium.base.SysUtils;
15 import org.chromium.base.ThreadUtils;
16 import org.chromium.base.annotations.AccessedByNative; 13 import org.chromium.base.annotations.AccessedByNative;
17 14
18 import java.io.FileNotFoundException;
19 import java.util.HashMap; 15 import java.util.HashMap;
20 import java.util.Locale; 16 import java.util.Locale;
21 import java.util.Map; 17 import java.util.Map;
22 18
23 import javax.annotation.Nullable; 19 import javax.annotation.Nullable;
24 20
25 /* 21 /*
26 * Technical note: 22 * Technical note:
27 * 23 *
28 * The point of this class is to provide an alternative to System.loadLibrary() 24 * The point of this class is to provide an alternative to System.loadLibrary()
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
146 * This Bundle must be passed to each service process, for example through 142 * This Bundle must be passed to each service process, for example through
147 * a Binder call (note that the Bundle includes file descriptors and cannot 143 * a Binder call (note that the Bundle includes file descriptors and cannot
148 * be added as an Intent extra). 144 * be added as an Intent extra).
149 * 145 *
150 * - In a service process, finishLibraryLoad() will block until the RELRO 146 * - In a service process, finishLibraryLoad() will block until the RELRO
151 * section Bundle is received. This is typically done by calling 147 * section Bundle is received. This is typically done by calling
152 * useSharedRelros() from another thread. 148 * useSharedRelros() from another thread.
153 * 149 *
154 * This method also ensures the process uses the shared RELROs. 150 * This method also ensures the process uses the shared RELROs.
155 */ 151 */
156 public class Linker { 152 public abstract class Linker {
157 153 // Log tag for this class.
158 // Log tag for this class. This must match the name of the linker's native l ibrary. 154 private static final String TAG = "cr.library_loader";
159 private static final String TAG = "chromium_android_linker";
160 155
161 // Set to true to enable debug logs. 156 // Set to true to enable debug logs.
162 private static final boolean DEBUG = false; 157 protected static final boolean DEBUG = false;
158
159 // Used to pass the shared RELRO Bundle through Binder.
160 public static final String EXTRA_LINKER_SHARED_RELROS =
161 "org.chromium.base.android.linker.shared_relros";
162
163 // Guards all access to the linker.
164 protected final Object mLock = new Object();
163 165
164 // Constants used to control the behaviour of the browser process with 166 // Constants used to control the behaviour of the browser process with
165 // regards to the shared RELRO section. 167 // regards to the shared RELRO section.
166 // NEVER -> The browser never uses it itself. 168 // NEVER -> The browser never uses it itself.
167 // LOW_RAM_ONLY -> It is only used on devices with low RAM. 169 // LOW_RAM_ONLY -> It is only used on devices with low RAM.
168 // ALWAYS -> It is always used. 170 // ALWAYS -> It is always used.
169 // NOTE: These names are known and expected by the Linker test scripts. 171 // NOTE: These names are known and expected by the Linker test scripts.
170 public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0; 172 public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0;
171 public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1; 173 public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1;
172 public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2; 174 public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2;
173 175
174 // Configuration variable used to control how the browser process uses the 176 // Configuration variable used to control how the browser process uses the
175 // shared RELRO. Only change this while debugging linker-related issues. 177 // shared RELRO. Only change this while debugging linker-related issues.
176 // NOTE: This variable's name is known and expected by the Linker test scrip ts. 178 // NOTE: This variable's name is known and expected by the Linker test scrip ts.
177 public static final int BROWSER_SHARED_RELRO_CONFIG = 179 public static final int BROWSER_SHARED_RELRO_CONFIG =
178 BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY; 180 BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY;
179 181
180 // Constants used to control the value of sMemoryDeviceConfig. 182 // Constants used to control the value of sMemoryDeviceConfig.
181 // INIT -> Value is undetermined (will check at runtime). 183 // INIT -> Value is undetermined (will check at runtime).
182 // LOW -> This is a low-memory device. 184 // LOW -> This is a low-memory device.
183 // NORMAL -> This is not a low-memory device. 185 // NORMAL -> This is not a low-memory device.
184 public static final int MEMORY_DEVICE_CONFIG_INIT = 0; 186 public static final int MEMORY_DEVICE_CONFIG_INIT = 0;
185 public static final int MEMORY_DEVICE_CONFIG_LOW = 1; 187 public static final int MEMORY_DEVICE_CONFIG_LOW = 1;
186 public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2; 188 public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2;
187 189
188 // Indicates if this is a low-memory device or not. The default is to 190 // Indicates if this is a low-memory device or not. The default is to
189 // determine this by probing the system at runtime, but this can be forced 191 // determine this by probing the system at runtime, but this can be forced
190 // for testing by calling setMemoryDeviceConfig(). 192 // for testing by calling setMemoryDeviceConfig().
191 private static int sMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT; 193 protected int mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
192 194
193 // Becomes true after linker initialization. 195 // Singleton.
194 private static boolean sInitialized = false; 196 private static Linker sSingleton = null;
197 private static Object sSingletonLock = new Object();
195 198
196 // Set to true to indicate that the system supports safe sharing of RELRO se ctions. 199 // Protected singleton constructor.
197 private static boolean sRelroSharingSupported = false; 200 protected Linker() {}
198 201
199 // Set to true if this runs in the browser process. Disabled by initServiceP rocess(). 202 // Get singleton instance.
200 // TODO(petrcermak): This flag can be incorrectly set to false (even though this might run in 203 public static final Linker getInstance() {
201 // the browser process) on low-memory devices. 204 synchronized (sSingletonLock) {
202 private static boolean sInBrowserProcess = true; 205 if (sSingleton == null) {
203 206 // TODO(simonb): Extend later to return either a LegacyLinker
204 // Becomes true to indicate this process needs to wait for a shared RELRO in 207 // or a ModernLinker instance.
205 // finishLibraryLoad(). 208 sSingleton = new LegacyLinker();
206 private static boolean sWaitForSharedRelros = false;
207
208 // Becomes true when initialization determines that the browser process can use the
209 // shared RELRO.
210 private static boolean sBrowserUsesSharedRelro = false;
211
212 // The map of all RELRO sections either created or used in this process.
213 private static Bundle sSharedRelros = null;
214
215 // Current common random base load address.
216 private static long sBaseLoadAddress = 0;
217
218 // Current fixed-location load address for the next library called by loadLi brary().
219 private static long sCurrentLoadAddress = 0;
220
221 // Becomes true once prepareLibraryLoad() has been called.
222 private static boolean sPrepareLibraryLoadCalled = false;
223
224 // Used internally to initialize the linker's static data. Assume lock is he ld.
225 private static void ensureInitializedLocked() {
226 assert Thread.holdsLock(Linker.class);
227
228 if (!sInitialized) {
229 sRelroSharingSupported = false;
230 if (NativeLibraries.sUseLinker) {
231 if (DEBUG) Log.i(TAG, "Loading lib" + TAG + ".so");
232 try {
233 System.loadLibrary(TAG);
234 } catch (UnsatisfiedLinkError e) {
235 // In a component build, the ".cr" suffix is added to each l ibrary name.
236 Log.w(TAG, "Couldn't load lib" + TAG + ".so, trying lib" + T AG + ".cr.so");
237 System.loadLibrary(TAG + ".cr");
238 }
239 sRelroSharingSupported = nativeCanUseSharedRelro();
240 if (!sRelroSharingSupported) {
241 Log.w(TAG, "This system cannot safely share RELRO sections") ;
242 } else {
243 if (DEBUG) Log.i(TAG, "This system supports safe shared RELR O sections");
244 }
245
246 if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
247 sMemoryDeviceConfig = SysUtils.isLowEndDevice()
248 ? MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NO RMAL;
249 }
250
251 switch (BROWSER_SHARED_RELRO_CONFIG) {
252 case BROWSER_SHARED_RELRO_CONFIG_NEVER:
253 sBrowserUsesSharedRelro = false;
254 break;
255 case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
256 sBrowserUsesSharedRelro =
257 (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW );
258 if (sBrowserUsesSharedRelro) {
259 Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
260 }
261 break;
262 case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
263 Log.w(TAG, "Beware: shared RELROs used in all processes! ");
264 sBrowserUsesSharedRelro = true;
265 break;
266 default:
267 assert false : "Unreached";
268 break;
269 }
270 } else {
271 if (DEBUG) Log.i(TAG, "Linker disabled");
272 } 209 }
273 210 return sSingleton;
274 if (!sRelroSharingSupported) {
275 // Sanity.
276 sBrowserUsesSharedRelro = false;
277 sWaitForSharedRelros = false;
278 }
279
280 sInitialized = true;
281 } 211 }
282 } 212 }
283 213
284 /** 214 /**
285 * A public interface used to run runtime linker tests after loading 215 * A public interface used to run runtime linker tests after loading
286 * libraries. Should only be used to implement the linker unit tests, 216 * libraries. Should only be used to implement the linker unit tests,
287 * which is controlled by the value of NativeLibraries.sEnableLinkerTests 217 * which is controlled by the value of NativeLibraries.sEnableLinkerTests
288 * configured at build time. 218 * configured at build time.
289 */ 219 */
290 public interface TestRunner { 220 public interface TestRunner {
291 /** 221 /**
292 * Run runtime checks and return true if they all pass. 222 * Run runtime checks and return true if they all pass.
293 * @param memoryDeviceConfig The current memory device configuration. 223 * @param memoryDeviceConfig The current memory device configuration.
294 * @param inBrowserProcess true iff this is the browser process. 224 * @param inBrowserProcess true iff this is the browser process.
295 */ 225 */
296 public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProces s); 226 public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProces s);
297 } 227 }
298 228
299 // The name of a class that implements TestRunner. 229 // The name of a class that implements TestRunner.
300 static String sTestRunnerClassName = null; 230 String mTestRunnerClassName = null;
301 231
302 /** 232 /**
303 * Set the TestRunner by its class name. It will be instantiated at 233 * Set the TestRunner by its class name. It will be instantiated at
304 * runtime after all libraries are loaded. 234 * runtime after all libraries are loaded.
305 * @param testRunnerClassName null or a String for the class name of the 235 * @param testRunnerClassName null or a String for the class name of the
306 * TestRunner to use. 236 * TestRunner to use.
307 */ 237 */
308 public static void setTestRunnerClassName(String testRunnerClassName) { 238 public void setTestRunnerClassName(String testRunnerClassName) {
309 if (DEBUG) Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") called"); 239 if (DEBUG) {
310 240 Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") ca lled");
241 }
311 if (!NativeLibraries.sEnableLinkerTests) { 242 if (!NativeLibraries.sEnableLinkerTests) {
312 // Ignore this in production code to prevent malvolent runtime injec tion. 243 // Ignore this in production code to prevent malevolent runtime inje ction.
313 return; 244 return;
314 } 245 }
315 246
316 synchronized (Linker.class) { 247 synchronized (mLock) {
317 assert sTestRunnerClassName == null; 248 assert mTestRunnerClassName == null;
318 sTestRunnerClassName = testRunnerClassName; 249 mTestRunnerClassName = testRunnerClassName;
319 } 250 }
320 } 251 }
321 252
322 /** 253 /**
323 * Call this to retrieve the name of the current TestRunner class name 254 * Call this to retrieve the name of the current TestRunner class name
324 * if any. This can be useful to pass it from the browser process to 255 * if any. This can be useful to pass it from the browser process to
325 * child ones. 256 * child ones.
326 * @return null or a String holding the name of the class implementing 257 * @return null or a String holding the name of the class implementing
327 * the TestRunner set by calling setTestRunnerClassName() previously. 258 * the TestRunner set by calling setTestRunnerClassName() previously.
328 */ 259 */
329 public static String getTestRunnerClassName() { 260 public String getTestRunnerClassName() {
330 synchronized (Linker.class) { 261 synchronized (mLock) {
331 return sTestRunnerClassName; 262 return mTestRunnerClassName;
332 } 263 }
333 } 264 }
334 265
335 /** 266 /**
336 * Call this method before any other Linker method to force a specific 267 * Call this method before any other Linker method to force a specific
337 * memory device configuration. Should only be used for testing. 268 * memory device configuration. Should only be used for testing.
338 * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVIC E_CONFIG_NORMAL. 269 * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVIC E_CONFIG_NORMAL.
339 */ 270 */
340 public static void setMemoryDeviceConfig(int memoryDeviceConfig) { 271 public void setMemoryDeviceConfig(int memoryDeviceConfig) {
341 if (DEBUG) Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called"); 272 if (DEBUG) {
273 Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called ");
274 }
342 // Sanity check. This method should only be called during tests. 275 // Sanity check. This method should only be called during tests.
343 assert NativeLibraries.sEnableLinkerTests; 276 assert NativeLibraries.sEnableLinkerTests;
344 synchronized (Linker.class) { 277 synchronized (mLock) {
345 assert sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT; 278 assert mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
346 assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW 279 assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
347 || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL; 280 || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
348 if (DEBUG) { 281 if (DEBUG) {
349 if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) { 282 if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
350 Log.i(TAG, "Simulating a low-memory device"); 283 Log.i(TAG, "Simulating a low-memory device");
351 } else { 284 } else {
352 Log.i(TAG, "Simulating a regular-memory device"); 285 Log.i(TAG, "Simulating a regular-memory device");
353 } 286 }
354 } 287 }
355 sMemoryDeviceConfig = memoryDeviceConfig; 288 mMemoryDeviceConfig = memoryDeviceConfig;
356 } 289 }
357 } 290 }
358 291
359 /** 292 /**
360 * Call this method to determine if this chromium project must 293 * Call this method to determine if this chromium project must
361 * use this linker. If not, System.loadLibrary() should be used to load 294 * use this linker. If not, System.loadLibrary() should be used to load
362 * libraries instead. 295 * libraries instead.
363 */ 296 */
364 public static boolean isUsed() { 297 public abstract boolean isUsed();
365 // Only GYP targets that are APKs and have the 'use_chromium_linker' var iable
366 // defined as 1 will use this linker. For all others (the default), the
367 // auto-generated NativeLibraries.sUseLinker variable will be false.
368 if (!NativeLibraries.sUseLinker) return false;
369
370 synchronized (Linker.class) {
371 ensureInitializedLocked();
372 // At the moment, there is also no point in using this linker if the
373 // system does not support RELRO sharing safely.
374 return sRelroSharingSupported;
375 }
376 }
377 298
378 /** 299 /**
379 * Call this method to determine if the linker will try to use shared RELROs 300 * Call this method to determine if the linker will try to use shared RELROs
380 * for the browser process. 301 * for the browser process.
381 */ 302 */
382 public static boolean isUsingBrowserSharedRelros() { 303 public abstract boolean isUsingBrowserSharedRelros();
383 synchronized (Linker.class) {
384 ensureInitializedLocked();
385 return sBrowserUsesSharedRelro;
386 }
387 }
388 304
389 /** 305 /**
390 * Call this method to determine if the chromium project must load 306 * Call this method to determine if the chromium project must load
391 * the library directly from the zip file. 307 * the library directly from the zip file.
392 */ 308 */
393 public static boolean isInZipFile() { 309 public abstract boolean isInZipFile();
394 return NativeLibraries.sUseLibraryInZipFile;
395 }
396 310
397 /** 311 /**
398 * Call this method just before loading any native shared libraries in this process. 312 * Call this method just before loading any native shared libraries in this process.
399 */ 313 */
400 public static void prepareLibraryLoad() { 314 public abstract void prepareLibraryLoad();
401 if (DEBUG) Log.i(TAG, "prepareLibraryLoad() called");
402 synchronized (Linker.class) {
403 sPrepareLibraryLoadCalled = true;
404
405 if (sInBrowserProcess) {
406 // Force generation of random base load address, as well
407 // as creation of shared RELRO sections in this process.
408 setupBaseLoadAddressLocked();
409 }
410 }
411 }
412 315
413 /** 316 /**
414 * Call this method just after loading all native shared libraries in this p rocess. 317 * Call this method just after loading all native shared libraries in this p rocess.
415 * Note that when in a service process, this will block until the RELRO bund le is 318 * Note that when in a service process, this will block until the RELRO bund le is
416 * received, i.e. when another thread calls useSharedRelros(). 319 * received, i.e. when another thread calls useSharedRelros().
417 */ 320 */
418 public static void finishLibraryLoad() { 321 public abstract void finishLibraryLoad();
419 if (DEBUG) Log.i(TAG, "finishLibraryLoad() called");
420 synchronized (Linker.class) {
421 if (DEBUG) Log.i(TAG, String.format(
422 Locale.US,
423 "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s sWaitForSha redRelros=%s",
424 sInBrowserProcess ? "true" : "false",
425 sBrowserUsesSharedRelro ? "true" : "false",
426 sWaitForSharedRelros ? "true" : "false"));
427
428 if (sLoadedLibraries == null) {
429 if (DEBUG) Log.i(TAG, "No libraries loaded");
430 } else {
431 if (sInBrowserProcess) {
432 // Create new Bundle containing RELRO section information
433 // for all loaded libraries. Make it available to getSharedR elros().
434 sSharedRelros = createBundleFromLibInfoMap(sLoadedLibraries) ;
435 if (DEBUG) {
436 Log.i(TAG, "Shared RELRO created");
437 dumpBundle(sSharedRelros);
438 }
439
440 if (sBrowserUsesSharedRelro) {
441 useSharedRelrosLocked(sSharedRelros);
442 }
443 }
444
445 if (sWaitForSharedRelros) {
446 assert !sInBrowserProcess;
447
448 // Wait until the shared relro bundle is received from useSh aredRelros().
449 while (sSharedRelros == null) {
450 try {
451 Linker.class.wait();
452 } catch (InterruptedException ie) {
453 // no-op
454 }
455 }
456 useSharedRelrosLocked(sSharedRelros);
457 // Clear the Bundle to ensure its file descriptor references can't be reused.
458 sSharedRelros.clear();
459 sSharedRelros = null;
460 }
461 }
462
463 if (NativeLibraries.sEnableLinkerTests && sTestRunnerClassName != nu ll) {
464 // The TestRunner implementation must be instantiated _after_
465 // all libraries are loaded to ensure that its native methods
466 // are properly registered.
467 if (DEBUG) Log.i(TAG, "Instantiating " + sTestRunnerClassName);
468 TestRunner testRunner = null;
469 try {
470 testRunner = (TestRunner)
471 Class.forName(sTestRunnerClassName).newInstance();
472 } catch (Exception e) {
473 Log.e(TAG, "Could not extract test runner class name", e);
474 testRunner = null;
475 }
476 if (testRunner != null) {
477 if (!testRunner.runChecks(sMemoryDeviceConfig, sInBrowserPro cess)) {
478 Log.wtf(TAG, "Linker runtime tests failed in this proces s!!");
479 assert false;
480 } else {
481 Log.i(TAG, "All linker tests passed!");
482 }
483 }
484 }
485 }
486 if (DEBUG) Log.i(TAG, "finishLibraryLoad() exiting");
487 }
488 322
489 /** 323 /**
490 * Call this to send a Bundle containing the shared RELRO sections to be 324 * Call this to send a Bundle containing the shared RELRO sections to be
491 * used in this process. If initServiceProcess() was previously called, 325 * used in this process. If initServiceProcess() was previously called,
492 * finishLibraryLoad() will not exit until this method is called in another 326 * finishLibraryLoad() will not exit until this method is called in another
493 * thread with a non-null value. 327 * thread with a non-null value.
494 * @param bundle The Bundle instance containing a map of shared RELRO sectio ns 328 * @param bundle The Bundle instance containing a map of shared RELRO sectio ns
495 * to use in this process. 329 * to use in this process.
496 */ 330 */
497 public static void useSharedRelros(Bundle bundle) { 331 public abstract void useSharedRelros(Bundle bundle);
498 // Ensure the bundle uses the application's class loader, not the framew ork
499 // one which doesn't know anything about LibInfo.
500 // Also, hold a fresh copy of it so the caller can't recycle it.
501 Bundle clonedBundle = null;
502 if (bundle != null) {
503 bundle.setClassLoader(LibInfo.class.getClassLoader());
504 clonedBundle = new Bundle(LibInfo.class.getClassLoader());
505 Parcel parcel = Parcel.obtain();
506 bundle.writeToParcel(parcel, 0);
507 parcel.setDataPosition(0);
508 clonedBundle.readFromParcel(parcel);
509 parcel.recycle();
510 }
511 if (DEBUG) {
512 Log.i(TAG, "useSharedRelros() called with " + bundle
513 + ", cloned " + clonedBundle);
514 }
515 synchronized (Linker.class) {
516 // Note that in certain cases, this can be called before
517 // initServiceProcess() in service processes.
518 sSharedRelros = clonedBundle;
519 // Tell any listener blocked in finishLibraryLoad() about it.
520 Linker.class.notifyAll();
521 }
522 }
523 332
524 /** 333 /**
525 * Call this to retrieve the shared RELRO sections created in this process, 334 * Call this to retrieve the shared RELRO sections created in this process,
526 * after loading all libraries. 335 * after loading all libraries.
527 * @return a new Bundle instance, or null if RELRO sharing is disabled on 336 * @return a new Bundle instance, or null if RELRO sharing is disabled on
528 * this system, or if initServiceProcess() was called previously. 337 * this system, or if initServiceProcess() was called previously.
529 */ 338 */
530 public static Bundle getSharedRelros() { 339 public abstract Bundle getSharedRelros();
531 if (DEBUG) Log.i(TAG, "getSharedRelros() called");
532 synchronized (Linker.class) {
533 if (!sInBrowserProcess) {
534 if (DEBUG) Log.i(TAG, "... returning null Bundle");
535 return null;
536 }
537
538 // Return the Bundle created in finishLibraryLoad().
539 if (DEBUG) Log.i(TAG, "... returning " + sSharedRelros);
540 return sSharedRelros;
541 }
542 }
543
544 340
545 /** 341 /**
546 * Call this method before loading any libraries to indicate that this 342 * Call this method before loading any libraries to indicate that this
547 * process shall neither create or reuse shared RELRO sections. 343 * process shall neither create or reuse shared RELRO sections.
548 */ 344 */
549 public static void disableSharedRelros() { 345 public abstract void disableSharedRelros();
550 if (DEBUG) Log.i(TAG, "disableSharedRelros() called");
551 synchronized (Linker.class) {
552 sInBrowserProcess = false;
553 sWaitForSharedRelros = false;
554 sBrowserUsesSharedRelro = false;
555 }
556 }
557 346
558 /** 347 /**
559 * Call this method before loading any libraries to indicate that this 348 * Call this method before loading any libraries to indicate that this
560 * process is ready to reuse shared RELRO sections from another one. 349 * process is ready to reuse shared RELRO sections from another one.
561 * Typically used when starting service processes. 350 * Typically used when starting service processes.
562 * @param baseLoadAddress the base library load address to use. 351 * @param baseLoadAddress the base library load address to use.
563 */ 352 */
564 public static void initServiceProcess(long baseLoadAddress) { 353 public abstract void initServiceProcess(long baseLoadAddress);
565 if (DEBUG) {
566 Log.i(TAG, String.format(
567 Locale.US, "initServiceProcess(0x%x) called", baseLoadAddres s));
568 }
569 synchronized (Linker.class) {
570 ensureInitializedLocked();
571 sInBrowserProcess = false;
572 sBrowserUsesSharedRelro = false;
573 if (sRelroSharingSupported) {
574 sWaitForSharedRelros = true;
575 sBaseLoadAddress = baseLoadAddress;
576 sCurrentLoadAddress = baseLoadAddress;
577 }
578 }
579 }
580 354
581 /** 355 /**
582 * Retrieve the base load address of all shared RELRO sections. 356 * Retrieve the base load address of all shared RELRO sections.
583 * This also enforces the creation of shared RELRO sections in 357 * This also enforces the creation of shared RELRO sections in
584 * prepareLibraryLoad(), which can later be retrieved with getSharedRelros() . 358 * prepareLibraryLoad(), which can later be retrieved with getSharedRelros() .
585 * @return a common, random base load address, or 0 if RELRO sharing is 359 * @return a common, random base load address, or 0 if RELRO sharing is
586 * disabled. 360 * disabled.
587 */ 361 */
588 public static long getBaseLoadAddress() { 362 public abstract long getBaseLoadAddress();
589 synchronized (Linker.class) {
590 ensureInitializedLocked();
591 if (!sInBrowserProcess) {
592 Log.w(TAG, "Shared RELRO sections are disabled in this process!" );
593 return 0;
594 }
595
596 setupBaseLoadAddressLocked();
597 if (DEBUG) Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress() returns 0x%x",
598 sBaseLoadAddress));
599 return sBaseLoadAddress;
600 }
601 }
602
603 // Used internally to lazily setup the common random base load address.
604 private static void setupBaseLoadAddressLocked() {
605 assert Thread.holdsLock(Linker.class);
606 if (sBaseLoadAddress == 0) {
607 long address = computeRandomBaseLoadAddress();
608 sBaseLoadAddress = address;
609 sCurrentLoadAddress = address;
610 if (address == 0) {
611 // If the computed address is 0, there are issues with finding e nough
612 // free address space, so disable RELRO shared / fixed load addr esses.
613 Log.w(TAG, "Disabling shared RELROs due address space pressure") ;
614 sBrowserUsesSharedRelro = false;
615 sWaitForSharedRelros = false;
616 }
617 }
618 }
619
620
621 /**
622 * Compute a random base load address at which to place loaded libraries.
623 * @return new base load address, or 0 if the system does not support
624 * RELRO sharing.
625 */
626 private static long computeRandomBaseLoadAddress() {
627 // nativeGetRandomBaseLoadAddress() returns an address at which it has p reviously
628 // successfully mapped an area of the given size, on the basis that we w ill be
629 // able, with high probability, to map our library into it.
630 //
631 // One issue with this is that we do not yet know the size of the librar y that
632 // we will load is. So here we pass a value that we expect will always b e larger
633 // than that needed. If it is smaller the library mapping may still succ eed. The
634 // other issue is that although highly unlikely, there is no guarantee t hat
635 // something else does not map into the area we are going to use between here and
636 // when we try to map into it.
637 //
638 // The above notes mean that all of this is probablistic. It is however okay to do
639 // because if, worst case and unlikely, we get unlucky in our choice of address,
640 // the back-out and retry without the shared RELRO in the ChildProcessSe rvice will
641 // keep things running.
642 final long maxExpectedBytes = 192 * 1024 * 1024;
643 final long address = nativeGetRandomBaseLoadAddress(maxExpectedBytes);
644 if (DEBUG) {
645 Log.i(TAG, String.format(Locale.US, "Random native base load address : 0x%x", address));
646 }
647 return address;
648 }
649
650 // Used for debugging only.
651 private static void dumpBundle(Bundle bundle) {
652 if (DEBUG) Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundl e);
653 }
654
655 /**
656 * Use the shared RELRO section from a Bundle received form another process.
657 * Call this after calling setBaseLoadAddress() then loading all libraries
658 * with loadLibrary().
659 * @param bundle Bundle instance generated with createSharedRelroBundle() in
660 * another process.
661 */
662 private static void useSharedRelrosLocked(Bundle bundle) {
663 assert Thread.holdsLock(Linker.class);
664
665 if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() called");
666
667 if (bundle == null) {
668 if (DEBUG) Log.i(TAG, "null bundle!");
669 return;
670 }
671
672 if (!sRelroSharingSupported) {
673 if (DEBUG) Log.i(TAG, "System does not support RELRO sharing");
674 return;
675 }
676
677 if (sLoadedLibraries == null) {
678 if (DEBUG) Log.i(TAG, "No libraries loaded!");
679 return;
680 }
681
682 if (DEBUG) dumpBundle(bundle);
683 HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
684
685 // Apply the RELRO section to all libraries that were already loaded.
686 for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
687 String libName = entry.getKey();
688 LibInfo libInfo = entry.getValue();
689 if (!nativeUseSharedRelro(libName, libInfo)) {
690 Log.w(TAG, "Could not use shared RELRO section for " + libName);
691 } else {
692 if (DEBUG) Log.i(TAG, "Using shared RELRO section for " + libNam e);
693 }
694 }
695
696 // In service processes, close all file descriptors from the map now.
697 if (!sInBrowserProcess) closeLibInfoMap(relroMap);
698
699 if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
700 }
701 363
702 /** 364 /**
703 * Load a native shared library with the Chromium linker. If the zip file 365 * Load a native shared library with the Chromium linker. If the zip file
704 * is not null, the shared library must be uncompressed and page aligned 366 * is not null, the shared library must be uncompressed and page aligned
705 * inside the zipfile. Note the crazy linker treats libraries and files as 367 * inside the zipfile. Note the crazy linker treats libraries and files as
706 * equivalent, so you can only open one library in a given zip file. The 368 * equivalent, so you can only open one library in a given zip file. The
707 * library must not be the Chromium linker library. 369 * library must not be the Chromium linker library.
708 * 370 *
709 * @param zipFilePath The path of the zip file containing the library (or nu ll). 371 * @param zipFilePath The path of the zip file containing the library (or nu ll).
710 * @param libFilePath The path of the library (possibly in the zip file). 372 * @param libFilePath The path of the library (possibly in the zip file).
711 */ 373 */
712 public static void loadLibrary(@Nullable String zipFilePath, String libFileP ath) { 374 public abstract void loadLibrary(@Nullable String zipFilePath, String libFil ePath);
713 if (DEBUG) Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath );
714
715 synchronized (Linker.class) {
716 ensureInitializedLocked();
717
718 // Security: Ensure prepareLibraryLoad() was called before.
719 // In theory, this can be done lazily here, but it's more consistent
720 // to use a pair of functions (i.e. prepareLibraryLoad() + finishLib raryLoad())
721 // that wrap all calls to loadLibrary() in the library loader.
722 assert sPrepareLibraryLoadCalled;
723
724 if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String, LibInfo>();
725
726 if (sLoadedLibraries.containsKey(libFilePath)) {
727 if (DEBUG) Log.i(TAG, "Not loading " + libFilePath + " twice");
728 return;
729 }
730
731 LibInfo libInfo = new LibInfo();
732 long loadAddress = 0;
733 if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForShared Relros) {
734 // Load the library at a fixed address.
735 loadAddress = sCurrentLoadAddress;
736 }
737
738 String sharedRelRoName = libFilePath;
739 if (zipFilePath != null) {
740 if (!nativeLoadLibraryInZipFile(zipFilePath, libFilePath, loadAd dress, libInfo)) {
741 String errorMessage = "Unable to load library: " + libFilePa th
742 + ", in: " + zipFilePath;
743 Log.e(TAG, errorMessage);
744 throw new UnsatisfiedLinkError(errorMessage);
745 }
746 sharedRelRoName = zipFilePath;
747 } else {
748 if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
749 String errorMessage = "Unable to load library: " + libFilePa th;
750 Log.e(TAG, errorMessage);
751 throw new UnsatisfiedLinkError(errorMessage);
752 }
753 }
754
755 // Print the load address to the logcat when testing the linker. The format
756 // of the string is expected by the Python test_runner script as one of:
757 // BROWSER_LIBRARY_ADDRESS: <library-name> <address>
758 // RENDERER_LIBRARY_ADDRESS: <library-name> <address>
759 // Where <library-name> is the library name, and <address> is the he xadecimal load
760 // address.
761 if (NativeLibraries.sEnableLinkerTests) {
762 Log.i(TAG, String.format(
763 Locale.US,
764 "%s_LIBRARY_ADDRESS: %s %x",
765 sInBrowserProcess ? "BROWSER" : "RENDERER",
766 libFilePath,
767 libInfo.mLoadAddress));
768 }
769
770 if (sInBrowserProcess) {
771 // Create a new shared RELRO section at the 'current' fixed load address.
772 if (!nativeCreateSharedRelro(sharedRelRoName, sCurrentLoadAddres s, libInfo)) {
773 Log.w(TAG, String.format(Locale.US,
774 "Could not create shared RELRO for %s at %x", libFil ePath,
775 sCurrentLoadAddress));
776 } else {
777 if (DEBUG) Log.i(TAG,
778 String.format(
779 Locale.US,
780 "Created shared RELRO for %s at %x: %s",
781 sharedRelRoName,
782 sCurrentLoadAddress,
783 libInfo.toString()));
784 }
785 }
786
787 if (sCurrentLoadAddress != 0) {
788 // Compute the next current load address. If sBaseLoadAddress
789 // is not 0, this is an explicit library load address. Otherwise ,
790 // this is an explicit load address for relocated RELRO sections
791 // only.
792 sCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
793 }
794
795 sLoadedLibraries.put(sharedRelRoName, libInfo);
796 if (DEBUG) Log.i(TAG, "Library details " + libInfo.toString());
797 }
798 }
799 375
800 /** 376 /**
801 * Determine whether a library is the linker library. Also deal with the 377 * Determine whether a library is the linker library. Also deal with the
802 * component build that adds a .cr suffix to the name. 378 * component build that adds a .cr suffix to the name.
803 */ 379 */
804 public static boolean isChromiumLinkerLibrary(String library) { 380 public abstract boolean isChromiumLinkerLibrary(String library);
805 return library.equals(TAG) || library.equals(TAG + ".cr");
806 }
807
808 /**
809 * Get the full library path in zip file (lib/<abi>/crazy.<lib_name>).
810 *
811 * @param library The library's base name.
812 * @return the library path.
813 */
814 public static String getLibraryFilePathInZipFile(String library) throws File NotFoundException {
815 synchronized (Linker.class) {
816 ensureInitializedLocked();
817
818 String path = nativeGetLibraryFilePathInZipFile(library);
819 if (path.equals("")) {
820 throw new FileNotFoundException(
821 "Failed to retrieve path in zip file for library " + lib rary);
822 }
823 return path;
824 }
825 }
826
827 /**
828 * Check whether a library is page aligned and uncompressed in the APK file.
829 *
830 * @param apkFile Filename of the APK.
831 * @param library The library's base name.
832 * @return true if page aligned and uncompressed.
833 */
834 public static boolean checkLibraryIsMappableInApk(String apkFile, String lib rary) {
835 synchronized (Linker.class) {
836 ensureInitializedLocked();
837
838 if (DEBUG) Log.i(TAG, "checkLibraryIsMappableInApk: " + apkFile + ", " + library);
839 boolean aligned = nativeCheckLibraryIsMappableInApk(apkFile, library );
840 if (DEBUG) Log.i(TAG, library + " is " + (aligned ? "" : "NOT ")
841 + "page aligned in " + apkFile);
842 return aligned;
843 }
844 }
845
846 /**
847 * Move activity from the native thread to the main UI thread.
848 * Called from native code on its own thread. Posts a callback from
849 * the UI thread back to native code.
850 *
851 * @param opaque Opaque argument.
852 */
853 @CalledByNative
854 public static void postCallbackOnMainThread(final long opaque) {
855 ThreadUtils.postOnUiThread(new Runnable() {
856 @Override
857 public void run() {
858 nativeRunCallbackOnUiThread(opaque);
859 }
860 });
861 }
862
863 /**
864 * Native method to run callbacks on the main UI thread.
865 * Supplied by the crazy linker and called by postCallbackOnMainThread.
866 * @param opaque Opaque crazy linker arguments.
867 */
868 private static native void nativeRunCallbackOnUiThread(long opaque);
869
870 /**
871 * Native method used to load a library.
872 * @param library Platform specific library name (e.g. libfoo.so)
873 * @param loadAddress Explicit load address, or 0 for randomized one.
874 * @param libInfo If not null, the mLoadAddress and mLoadSize fields
875 * of this LibInfo instance will set on success.
876 * @return true for success, false otherwise.
877 */
878 private static native boolean nativeLoadLibrary(String library,
879 long loadAddress,
880 LibInfo libInfo);
881
882 /**
883 * Native method used to load a library which is inside a zipfile.
884 * @param zipfileName Filename of the zip file containing the library.
885 * @param library Platform specific library name (e.g. libfoo.so)
886 * @param loadAddress Explicit load address, or 0 for randomized one.
887 * @param libInfo If not null, the mLoadAddress and mLoadSize fields
888 * of this LibInfo instance will set on success.
889 * @return true for success, false otherwise.
890 */
891 private static native boolean nativeLoadLibraryInZipFile(String zipfileName,
892 String libraryName,
893 long loadAddress,
894 LibInfo libInfo);
895
896 /**
897 * Native method used to create a shared RELRO section.
898 * If the library was already loaded at the same address using
899 * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
900 * this loads a new temporary library at the specified address,
901 * creates and extracts the RELRO section from it, then unloads it.
902 * @param library Library name.
903 * @param loadAddress load address, which can be different from the one
904 * used to load the library in the current process!
905 * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
906 * and mRelroFd will be set.
907 * @return true on success, false otherwise.
908 */
909 private static native boolean nativeCreateSharedRelro(String library,
910 long loadAddress,
911 LibInfo libInfo);
912
913 /**
914 * Native method used to use a shared RELRO section.
915 * @param library Library name.
916 * @param libInfo A LibInfo instance containing valid RELRO information
917 * @return true on success.
918 */
919 private static native boolean nativeUseSharedRelro(String library,
920 LibInfo libInfo);
921
922 /**
923 * Checks that the system supports shared RELROs. Old Android kernels
924 * have a bug in the way they check Ashmem region protection flags, which
925 * makes using shared RELROs unsafe. This method performs a simple runtime
926 * check for this misfeature, even though nativeEnableSharedRelro() will
927 * always fail if this returns false.
928 */
929 private static native boolean nativeCanUseSharedRelro();
930
931 /**
932 * Return a random address that should be free to be mapped with the given s ize.
933 * Maps an area of size bytes, and if successful then unmaps it and returns
934 * the address of the area allocated by the system (with ASLR). The idea is
935 * that this area should remain free of other mappings until we map our libr ary
936 * into it.
937 * @param sizeBytes Size of area in bytes to search for.
938 * @return address to pass to future mmap, or 0 on error.
939 */
940 private static native long nativeGetRandomBaseLoadAddress(long sizeBytes);
941
942 /**
943 * Native method used to get the full library path in zip file
944 * (lib/<abi>/crazy.<lib_name>).
945 *
946 * @param library The library's base name.
947 * @return the library path (or empty string on failure).
948 */
949 private static native String nativeGetLibraryFilePathInZipFile(String librar y);
950
951 /**
952 * Native method which checks whether a library is page aligned and
953 * uncompressed in the APK file.
954 *
955 * @param apkFile Filename of the APK.
956 * @param library The library's base name.
957 * @return true if page aligned and uncompressed.
958 */
959 private static native boolean nativeCheckLibraryIsMappableInApk(String apkFi le, String library);
960 381
961 /** 382 /**
962 * Record information for a given library. 383 * Record information for a given library.
963 * IMPORTANT: Native code knows about this class's fields, so 384 * IMPORTANT: Native code knows about this class's fields, so
964 * don't change them without modifying the corresponding C++ sources. 385 * don't change them without modifying the corresponding C++ sources.
965 * Also, the LibInfo instance owns the ashmem file descriptor. 386 * Also, the LibInfo instance owns the ashmem file descriptor.
966 */ 387 */
967 public static class LibInfo implements Parcelable { 388 public static class LibInfo implements Parcelable {
968 389
969 public LibInfo() { 390 public LibInfo() {
970 mLoadAddress = 0; 391 mLoadAddress = 0;
971 mLoadSize = 0; 392 mLoadSize = 0;
972 mRelroStart = 0; 393 mRelroStart = 0;
973 mRelroSize = 0; 394 mRelroSize = 0;
974 mRelroFd = -1; 395 mRelroFd = -1;
975 } 396 }
976 397
977 public void close() { 398 public void close() {
978 if (mRelroFd >= 0) { 399 if (mRelroFd >= 0) {
979 try { 400 try {
980 ParcelFileDescriptor.adoptFd(mRelroFd).close(); 401 ParcelFileDescriptor.adoptFd(mRelroFd).close();
981 } catch (java.io.IOException e) { 402 } catch (java.io.IOException e) {
982 if (DEBUG) Log.e(TAG, "Failed to close fd: " + mRelroFd); 403 if (DEBUG) {
404 Log.e(TAG, "Failed to close fd: " + mRelroFd);
405 }
983 } 406 }
984 mRelroFd = -1; 407 mRelroFd = -1;
985 } 408 }
986 } 409 }
987 410
988 // from Parcelable 411 // from Parcelable
989 public LibInfo(Parcel in) { 412 public LibInfo(Parcel in) {
990 mLoadAddress = in.readLong(); 413 mLoadAddress = in.readLong();
991 mLoadSize = in.readLong(); 414 mLoadSize = in.readLong();
992 mRelroStart = in.readLong(); 415 mRelroStart = in.readLong();
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
1053 public long mLoadSize; // page-aligned library load size. 476 public long mLoadSize; // page-aligned library load size.
1054 @AccessedByNative 477 @AccessedByNative
1055 public long mRelroStart; // page-aligned address in memory, or 0 if non e. 478 public long mRelroStart; // page-aligned address in memory, or 0 if non e.
1056 @AccessedByNative 479 @AccessedByNative
1057 public long mRelroSize; // page-aligned size in memory, or 0. 480 public long mRelroSize; // page-aligned size in memory, or 0.
1058 @AccessedByNative 481 @AccessedByNative
1059 public int mRelroFd; // ashmem file descriptor, or -1 482 public int mRelroFd; // ashmem file descriptor, or -1
1060 } 483 }
1061 484
1062 // Create a Bundle from a map of LibInfo objects. 485 // Create a Bundle from a map of LibInfo objects.
1063 private static Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> ma p) { 486 protected Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
1064 Bundle bundle = new Bundle(map.size()); 487 Bundle bundle = new Bundle(map.size());
1065 for (Map.Entry<String, LibInfo> entry : map.entrySet()) { 488 for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
1066 bundle.putParcelable(entry.getKey(), entry.getValue()); 489 bundle.putParcelable(entry.getKey(), entry.getValue());
1067 } 490 }
1068 491
1069 return bundle; 492 return bundle;
1070 } 493 }
1071 494
1072 // Create a new LibInfo map from a Bundle. 495 // Create a new LibInfo map from a Bundle.
1073 private static HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bu ndle) { 496 protected HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
1074 HashMap<String, LibInfo> map = new HashMap<String, LibInfo>(); 497 HashMap<String, LibInfo> map = new HashMap<String, LibInfo>();
1075 for (String library : bundle.keySet()) { 498 for (String library : bundle.keySet()) {
1076 LibInfo libInfo = bundle.getParcelable(library); 499 LibInfo libInfo = bundle.getParcelable(library);
1077 map.put(library, libInfo); 500 map.put(library, libInfo);
1078 } 501 }
1079 return map; 502 return map;
1080 } 503 }
1081 504
1082 // Call the close() method on all values of a LibInfo map. 505 // Call the close() method on all values of a LibInfo map.
1083 private static void closeLibInfoMap(HashMap<String, LibInfo> map) { 506 protected void closeLibInfoMap(HashMap<String, LibInfo> map) {
1084 for (Map.Entry<String, LibInfo> entry : map.entrySet()) { 507 for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
1085 entry.getValue().close(); 508 entry.getValue().close();
1086 } 509 }
1087 } 510 }
1088
1089 // The map of libraries that are currently loaded in this process.
1090 private static HashMap<String, LibInfo> sLoadedLibraries = null;
1091
1092 // Used to pass the shared RELRO Bundle through Binder.
1093 public static final String EXTRA_LINKER_SHARED_RELROS =
1094 "org.chromium.base.android.linker.shared_relros";
1095 } 511 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698