/** * Call this method to determine if this chromium project must use this linker. If not, * System.loadLibrary() should be used to load libraries instead. */ public static boolean isUsed() { // Only GYP targets that are APKs and have the 'use_chromium_linker' variable // defined as 1 will use this linker. For all others (the default), the // auto-generated NativeLibraries.USE_LINKER variable will be false. if (!NativeLibraries.USE_LINKER) return false; synchronized (Linker.class) { ensureInitializedLocked(); // At the moment, there is also no point in using this linker if the // system does not support RELRO sharing safely. return sRelroSharingSupported; } }
/** * Retrieve the base load address of all shared RELRO sections. This also enforces the creation of * shared RELRO sections in prepareLibraryLoad(), which can later be retrieved with * getSharedRelros(). * * @return a common, random base load address, or 0 if RELRO sharing is disabled. */ public static long getBaseLoadAddress() { synchronized (Linker.class) { ensureInitializedLocked(); if (!sInBrowserProcess) { Log.w(TAG, "Shared RELRO sections are disabled in this process!"); return 0; } setupBaseLoadAddressLocked(); if (DEBUG) Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress() returns 0x%x", sBaseLoadAddress)); return sBaseLoadAddress; } }
/** * Call this method before loading any libraries to indicate that this process is ready to reuse * shared RELRO sections from another one. Typically used when starting service processes. * * @param baseLoadAddress the base library load address to use. */ public static void initServiceProcess(long baseLoadAddress) { if (DEBUG) { Log.i(TAG, String.format(Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress)); } synchronized (Linker.class) { ensureInitializedLocked(); sInBrowserProcess = false; sBrowserUsesSharedRelro = false; if (sRelroSharingSupported) { sWaitForSharedRelros = true; sBaseLoadAddress = baseLoadAddress; sCurrentLoadAddress = baseLoadAddress; } } }
/** * Load a native shared library with the Chromium linker. If neither initSharedRelro() or * readFromBundle() were called previously, this uses the standard linker (i.e. * System.loadLibrary()). * * @param library The library's base name. */ public static void loadLibrary(String library) { if (DEBUG) Log.i(TAG, "loadLibrary: " + library); // Don't self-load the linker. This is because the build system is // not clever enough to understand that all the libraries packaged // in the final .apk don't need to be explicitly loaded. // Also deal with the component build that adds a .cr suffix to the name. if (library.equals(TAG) || library.equals(TAG + ".cr")) { if (DEBUG) Log.i(TAG, "ignoring self-linker load"); return; } synchronized (Linker.class) { ensureInitializedLocked(); // Security: Ensure prepareLibraryLoad() was called before. // In theory, this can be done lazily here, but it's more consistent // to use a pair of functions (i.e. prepareLibraryLoad() + finishLibraryLoad()) // that wrap all calls to loadLibrary() in the library loader. assert sPrepareLibraryLoadCalled; String libName = System.mapLibraryName(library); if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String, LibInfo>(); if (sLoadedLibraries.containsKey(libName)) { if (DEBUG) Log.i(TAG, "Not loading " + libName + " twice"); return; } LibInfo libInfo = new LibInfo(); long loadAddress = 0; if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForSharedRelros) { // Load the library at a fixed address. loadAddress = sCurrentLoadAddress; } if (!nativeLoadLibrary(libName, loadAddress, libInfo)) { String errorMessage = "Unable to load library: " + libName; Log.e(TAG, errorMessage); throw new UnsatisfiedLinkError(errorMessage); } // Keep track whether the library has been loaded at the expected load address. if (loadAddress != 0 && loadAddress != libInfo.mLoadAddress) sLoadAtFixedAddressFailed = true; // Print the load address to the logcat when testing the linker. The format // of the string is expected by the Python test_runner script as one of: // BROWSER_LIBRARY_ADDRESS: <library-name> <address> // RENDERER_LIBRARY_ADDRESS: <library-name> <address> // Where <library-name> is the library name, and <address> is the hexadecimal load // address. if (NativeLibraries.ENABLE_LINKER_TESTS) { Log.i( TAG, String.format( Locale.US, "%s_LIBRARY_ADDRESS: %s %x", sInBrowserProcess ? "BROWSER" : "RENDERER", libName, libInfo.mLoadAddress)); } if (sInBrowserProcess) { // Create a new shared RELRO section at the 'current' fixed load address. if (!nativeCreateSharedRelro(libName, sCurrentLoadAddress, libInfo)) { Log.w( TAG, String.format( Locale.US, "Could not create shared RELRO for %s at %x", libName, sCurrentLoadAddress)); } else { if (DEBUG) Log.i( TAG, String.format( Locale.US, "Created shared RELRO for %s at %x: %s", libName, sCurrentLoadAddress, libInfo.toString())); } } if (sCurrentLoadAddress != 0) { // Compute the next current load address. If sBaseLoadAddress // is not 0, this is an explicit library load address. Otherwise, // this is an explicit load address for relocated RELRO sections // only. sCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize; } sLoadedLibraries.put(libName, libInfo); if (DEBUG) Log.i(TAG, "Library details " + libInfo.toString()); } }