OLD | NEW |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |