Commit 51ca0822 authored by petrcermak's avatar petrcermak Committed by Commit bot

Library loading fallback.

This patch adds support for copying the Chromium library from the APK file
to a separate file.

This patch is largly based on https://codereview.chromium.org/673093005/.

BUG=390618

Review URL: https://codereview.chromium.org/684163002

Cr-Commit-Position: refs/heads/master@{#302456}
parent 04f14479
...@@ -12,6 +12,8 @@ import org.chromium.base.CommandLine; ...@@ -12,6 +12,8 @@ import org.chromium.base.CommandLine;
import org.chromium.base.JNINamespace; import org.chromium.base.JNINamespace;
import org.chromium.base.TraceEvent; import org.chromium.base.TraceEvent;
import javax.annotation.Nullable;
/** /**
* This class provides functionality to load and register the native libraries. * This class provides functionality to load and register the native libraries.
* Callers are allowed to separate loading the libraries from initializing them. * Callers are allowed to separate loading the libraries from initializing them.
...@@ -53,8 +55,12 @@ public class LibraryLoader { ...@@ -53,8 +55,12 @@ public class LibraryLoader {
private static boolean sIsUsingBrowserSharedRelros = false; private static boolean sIsUsingBrowserSharedRelros = false;
private static boolean sLoadAtFixedAddressFailed = false; private static boolean sLoadAtFixedAddressFailed = false;
// One-way switch becomes true if the library was loaded from the APK file // One-way switch becomes true if the device supports loading the Chromium
// directly. // library directly from the APK.
private static boolean sLibraryLoadFromApkSupported = false;
// One-way switch becomes true if the Chromium library was loaded from the
// APK file directly.
private static boolean sLibraryWasLoadedFromApk = false; private static boolean sLibraryWasLoadedFromApk = false;
// One-way switch becomes false if the Chromium library should be loaded // One-way switch becomes false if the Chromium library should be loaded
...@@ -91,7 +97,7 @@ public class LibraryLoader { ...@@ -91,7 +97,7 @@ public class LibraryLoader {
* http://b/13216167. * http://b/13216167.
* *
* @param shouldDeleteOldWorkaroundLibraries The flag tells whether the method * @param shouldDeleteOldWorkaroundLibraries The flag tells whether the method
* should delete the old workaround libraries or not. * should delete the old workaround and fallback libraries or not.
*/ */
public static void ensureInitialized( public static void ensureInitialized(
Context context, boolean shouldDeleteOldWorkaroundLibraries) Context context, boolean shouldDeleteOldWorkaroundLibraries)
...@@ -134,7 +140,7 @@ public class LibraryLoader { ...@@ -134,7 +140,7 @@ public class LibraryLoader {
* *
* @param context The context the code is running, or null if it doesn't have one. * @param context The context the code is running, or null if it doesn't have one.
* @param shouldDeleteOldWorkaroundLibraries The flag tells whether the method * @param shouldDeleteOldWorkaroundLibraries The flag tells whether the method
* should delete the old workaround libraries or not. * should delete the old workaround and fallback libraries or not.
* *
* @throws ProcessInitException if the native library failed to load. * @throws ProcessInitException if the native library failed to load.
*/ */
...@@ -166,8 +172,20 @@ public class LibraryLoader { ...@@ -166,8 +172,20 @@ public class LibraryLoader {
long startTime = SystemClock.uptimeMillis(); long startTime = SystemClock.uptimeMillis();
boolean useChromiumLinker = Linker.isUsed(); boolean useChromiumLinker = Linker.isUsed();
boolean fallbackWasUsed = false;
if (useChromiumLinker) { if (useChromiumLinker) {
String apkFilePath = null;
// Check if the device supports loading a library directly from the APK file.
if (context != null) {
apkFilePath = context.getApplicationInfo().sourceDir;
sLibraryLoadFromApkSupported = Linker.checkLibraryLoadFromApkSupport(
apkFilePath);
} else {
Log.w(TAG, "could not check load from APK support due to null context");
}
// Load libraries using the Chromium linker. // Load libraries using the Chromium linker.
Linker.prepareLibraryLoad(); Linker.prepareLibraryLoad();
...@@ -180,26 +198,40 @@ public class LibraryLoader { ...@@ -180,26 +198,40 @@ public class LibraryLoader {
continue; continue;
} }
String zipfile = null; // Determine where the library should be loaded from.
if (Linker.isInZipFile()) { String zipFilePath = null;
zipfile = context.getApplicationInfo().sourceDir; String libFilePath = System.mapLibraryName(library);
sLibraryWasAlignedInApk = Linker.checkLibraryAlignedInApk( if (apkFilePath != null && Linker.isInZipFile()) {
zipfile, System.mapLibraryName(library)); // The library is in the APK file.
Log.i(TAG, "Loading " + library + " from within " + zipfile); if (!Linker.checkLibraryAlignedInApk(apkFilePath, libFilePath)) {
sLibraryWasAlignedInApk = false;
}
if (!sLibraryLoadFromApkSupported || sLibraryWasAlignedInApk) {
// Load directly from the APK (or use memory fallback, see
// crazy_linker_elf_loader.cpp).
Log.i(TAG, "Loading " + library + " directly from within "
+ apkFilePath);
zipFilePath = apkFilePath;
} else {
// Fallback.
Log.i(TAG, "Loading " + library + " using fallback from within "
+ apkFilePath);
libFilePath = LibraryLoaderHelper.buildFallbackLibrary(
context, library);
fallbackWasUsed = true;
Log.i(TAG, "Built fallback library " + libFilePath);
}
} else { } else {
Log.i(TAG, "Loading: " + library); // The library is in its own file.
Log.i(TAG, "Loading " + library);
} }
// Load the library.
boolean isLoaded = false; boolean isLoaded = false;
if (Linker.isUsingBrowserSharedRelros()) { if (Linker.isUsingBrowserSharedRelros()) {
sIsUsingBrowserSharedRelros = true; sIsUsingBrowserSharedRelros = true;
try { try {
if (zipfile != null) { loadLibrary(zipFilePath, libFilePath);
Linker.loadLibraryInZipFile(zipfile, library);
sLibraryWasLoadedFromApk = true;
} else {
Linker.loadLibrary(library);
}
isLoaded = true; isLoaded = true;
} catch (UnsatisfiedLinkError e) { } catch (UnsatisfiedLinkError e) {
Log.w(TAG, "Failed to load native library with shared RELRO, " Log.w(TAG, "Failed to load native library with shared RELRO, "
...@@ -209,12 +241,7 @@ public class LibraryLoader { ...@@ -209,12 +241,7 @@ public class LibraryLoader {
} }
} }
if (!isLoaded) { if (!isLoaded) {
if (zipfile != null) { loadLibrary(zipFilePath, libFilePath);
Linker.loadLibraryInZipFile(zipfile, library);
sLibraryWasLoadedFromApk = true;
} else {
Linker.loadLibrary(library);
}
} }
} }
...@@ -227,7 +254,7 @@ public class LibraryLoader { ...@@ -227,7 +254,7 @@ public class LibraryLoader {
} catch (UnsatisfiedLinkError e) { } catch (UnsatisfiedLinkError e) {
if (context != null if (context != null
&& LibraryLoaderHelper.tryLoadLibraryUsingWorkaround(context, && LibraryLoaderHelper.tryLoadLibraryUsingWorkaround(context,
library)) { library)) {
sNativeLibraryHackWasUsed = true; sNativeLibraryHackWasUsed = true;
} else { } else {
throw e; throw e;
...@@ -236,11 +263,15 @@ public class LibraryLoader { ...@@ -236,11 +263,15 @@ public class LibraryLoader {
} }
} }
if (context != null if (context != null && shouldDeleteOldWorkaroundLibraries) {
&& shouldDeleteOldWorkaroundLibraries if (!sNativeLibraryHackWasUsed) {
&& !sNativeLibraryHackWasUsed) { LibraryLoaderHelper.deleteLibrariesAsynchronously(
LibraryLoaderHelper.deleteWorkaroundLibrariesAsynchronously( context, LibraryLoaderHelper.PACKAGE_MANAGER_WORKAROUND_DIR);
context); }
if (!fallbackWasUsed) {
LibraryLoaderHelper.deleteLibrariesAsynchronously(
context, LibraryLoaderHelper.LOAD_FROM_APK_FALLBACK_DIR);
}
} }
long stopTime = SystemClock.uptimeMillis(); long stopTime = SystemClock.uptimeMillis();
...@@ -265,6 +296,15 @@ public class LibraryLoader { ...@@ -265,6 +296,15 @@ public class LibraryLoader {
} }
} }
// Load a native shared library with the Chromium linker. If the zip file
// path is not null, the library is loaded directly from the zip file.
private static void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
if (zipFilePath != null) {
sLibraryWasLoadedFromApk = true;
}
Linker.loadLibrary(zipFilePath, libFilePath);
}
// The WebView requires the Command Line to be switched over before // The WebView requires the Command Line to be switched over before
// initialization is done. This is okay in the WebView's case since the // initialization is done. This is okay in the WebView's case since the
// JNI is already loaded by this point. // JNI is already loaded by this point.
......
...@@ -15,6 +15,7 @@ import org.chromium.base.CalledByNative; ...@@ -15,6 +15,7 @@ import org.chromium.base.CalledByNative;
import org.chromium.base.SysUtils; import org.chromium.base.SysUtils;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import java.io.FileNotFoundException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
...@@ -699,33 +700,17 @@ public class Linker { ...@@ -699,33 +700,17 @@ public class Linker {
} }
/** /**
* Load a native shared library with the Chromium linker. * Load a native shared library with the Chromium linker. If the zip file
* The shared library is uncompressed and page aligned inside the zipfile. * is not null, the shared library must be uncompressed and page aligned
* Note the crazy linker treats libraries and files as equivalent, * inside the zipfile. Note the crazy linker treats libraries and files as
* so you can only open one library in a given zip file. The library must * equivalent, so you can only open one library in a given zip file. The
* not be the Chromium linker library. * library must not be the Chromium linker library.
* *
* @param zipfile The filename of the zipfile contain the library. * @param zipFilePath The path of the zip file containing the library (or null).
* @param library The library's base name. * @param libFilePath The path of the library (possibly in the zip file).
*/
public static void loadLibraryInZipFile(String zipfile, String library) {
loadLibraryMaybeInZipFile(zipfile, library);
}
/**
* Load a native shared library with the Chromium linker. The library must
* not be the Chromium linker library.
*
* @param library The library's base name.
*/ */
public static void loadLibrary(String library) { public static void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
loadLibraryMaybeInZipFile(null, library); if (DEBUG) Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath);
}
private static void loadLibraryMaybeInZipFile(
@Nullable String zipFile, String library) {
if (DEBUG) Log.i(TAG, "loadLibrary: " + library);
assert !isChromiumLinkerLibrary(library);
synchronized (Linker.class) { synchronized (Linker.class) {
ensureInitializedLocked(); ensureInitializedLocked();
...@@ -736,12 +721,10 @@ public class Linker { ...@@ -736,12 +721,10 @@ public class Linker {
// that wrap all calls to loadLibrary() in the library loader. // that wrap all calls to loadLibrary() in the library loader.
assert sPrepareLibraryLoadCalled; assert sPrepareLibraryLoadCalled;
String libName = System.mapLibraryName(library);
if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String, LibInfo>(); if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String, LibInfo>();
if (sLoadedLibraries.containsKey(libName)) { if (sLoadedLibraries.containsKey(libFilePath)) {
if (DEBUG) Log.i(TAG, "Not loading " + libName + " twice"); if (DEBUG) Log.i(TAG, "Not loading " + libFilePath + " twice");
return; return;
} }
...@@ -752,18 +735,18 @@ public class Linker { ...@@ -752,18 +735,18 @@ public class Linker {
loadAddress = sCurrentLoadAddress; loadAddress = sCurrentLoadAddress;
} }
String sharedRelRoName = libName; String sharedRelRoName = libFilePath;
if (zipFile != null) { if (zipFilePath != null) {
if (!nativeLoadLibraryInZipFile(zipFile, libName, loadAddress, libInfo)) { if (!nativeLoadLibraryInZipFile(zipFilePath, libFilePath, loadAddress, libInfo)) {
String errorMessage = "Unable to load library: " + libName String errorMessage = "Unable to load library: " + libFilePath
+ ", in: " + zipFile; + ", in: " + zipFilePath;
Log.e(TAG, errorMessage); Log.e(TAG, errorMessage);
throw new UnsatisfiedLinkError(errorMessage); throw new UnsatisfiedLinkError(errorMessage);
} }
sharedRelRoName = zipFile; sharedRelRoName = zipFilePath;
} else { } else {
if (!nativeLoadLibrary(libName, loadAddress, libInfo)) { if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
String errorMessage = "Unable to load library: " + libName; String errorMessage = "Unable to load library: " + libFilePath;
Log.e(TAG, errorMessage); Log.e(TAG, errorMessage);
throw new UnsatisfiedLinkError(errorMessage); throw new UnsatisfiedLinkError(errorMessage);
} }
...@@ -780,7 +763,7 @@ public class Linker { ...@@ -780,7 +763,7 @@ public class Linker {
Locale.US, Locale.US,
"%s_LIBRARY_ADDRESS: %s %x", "%s_LIBRARY_ADDRESS: %s %x",
sInBrowserProcess ? "BROWSER" : "RENDERER", sInBrowserProcess ? "BROWSER" : "RENDERER",
libName, libFilePath,
libInfo.mLoadAddress)); libInfo.mLoadAddress));
} }
...@@ -788,7 +771,7 @@ public class Linker { ...@@ -788,7 +771,7 @@ public class Linker {
// Create a new shared RELRO section at the 'current' fixed load address. // Create a new shared RELRO section at the 'current' fixed load address.
if (!nativeCreateSharedRelro(sharedRelRoName, sCurrentLoadAddress, libInfo)) { if (!nativeCreateSharedRelro(sharedRelRoName, sCurrentLoadAddress, libInfo)) {
Log.w(TAG, String.format(Locale.US, Log.w(TAG, String.format(Locale.US,
"Could not create shared RELRO for %s at %x", libName, "Could not create shared RELRO for %s at %x", libFilePath,
sCurrentLoadAddress)); sCurrentLoadAddress));
} else { } else {
if (DEBUG) Log.i(TAG, if (DEBUG) Log.i(TAG,
...@@ -822,6 +805,21 @@ public class Linker { ...@@ -822,6 +805,21 @@ public class Linker {
return library.equals(TAG) || library.equals(TAG + ".cr"); return library.equals(TAG) || library.equals(TAG + ".cr");
} }
/**
* Get the full library path in zip file (lib/<abi>/crazy.<lib_name>).
*
* @param library The library's base name.
* @return the library path.
*/
public static String getLibraryFilePathInZipFile(String library) throws FileNotFoundException {
String path = nativeGetLibraryFilePathInZipFile(library);
if (path.equals("")) {
throw new FileNotFoundException(
"Failed to retrieve path in zip file for library " + library);
}
return path;
}
/** /**
* Check whether the device supports loading a library directly from the APK file. * Check whether the device supports loading a library directly from the APK file.
* *
...@@ -854,8 +852,8 @@ public class Linker { ...@@ -854,8 +852,8 @@ public class Linker {
if (DEBUG) Log.i(TAG, "checkLibraryAlignedInApk: " + apkFile + ", " + library); if (DEBUG) Log.i(TAG, "checkLibraryAlignedInApk: " + apkFile + ", " + library);
boolean aligned = nativeCheckLibraryAlignedInApk(apkFile, library); boolean aligned = nativeCheckLibraryAlignedInApk(apkFile, library);
if (DEBUG) Log.i(TAG, library + " is " + (aligned ? "" : "NOT ") + if (DEBUG) Log.i(TAG, library + " is " + (aligned ? "" : "NOT ")
"page aligned in " + apkFile); + "page aligned in " + apkFile);
return aligned; return aligned;
} }
} }
...@@ -956,6 +954,15 @@ public class Linker { ...@@ -956,6 +954,15 @@ public class Linker {
*/ */
private static native long nativeGetRandomBaseLoadAddress(long sizeBytes); private static native long nativeGetRandomBaseLoadAddress(long sizeBytes);
/**
* Native method used to get the full library path in zip file
* (lib/<abi>/crazy.<lib_name>).
*
* @param library The library's base name.
* @return the library path (or empty string on failure).
*/
private static native String nativeGetLibraryFilePathInZipFile(String library);
/** /**
* Native method which checks whether the device supports loading a library * Native method which checks whether the device supports loading a library
* directly from the APK file. * directly from the APK file.
......
...@@ -21,7 +21,8 @@ public class LibraryLoaderHelperTest extends InstrumentationTestCase { ...@@ -21,7 +21,8 @@ public class LibraryLoaderHelperTest extends InstrumentationTestCase {
@Override @Override
public void setUp() throws Exception { public void setUp() throws Exception {
Context context = getInstrumentation().getTargetContext(); Context context = getInstrumentation().getTargetContext();
LibraryLoaderHelper.deleteWorkaroundLibrariesSynchronously(context); LibraryLoaderHelper.deleteLibrariesSynchronously(
context, LibraryLoaderHelper.PACKAGE_MANAGER_WORKAROUND_DIR);
} }
@MediumTest @MediumTest
...@@ -30,13 +31,13 @@ public class LibraryLoaderHelperTest extends InstrumentationTestCase { ...@@ -30,13 +31,13 @@ public class LibraryLoaderHelperTest extends InstrumentationTestCase {
@Override @Override
public void run() { public void run() {
Context context = getInstrumentation().getTargetContext(); Context context = getInstrumentation().getTargetContext();
File libDir = LibraryLoaderHelper.getWorkaroundLibDir(context); File libDir = LibraryLoaderHelper.getLibDir(context,
LibraryLoaderHelper.PACKAGE_MANAGER_WORKAROUND_DIR);
assertTrue(libDir.exists()); assertTrue(libDir.exists());
assertTrue(libDir.isDirectory()); assertTrue(libDir.isDirectory());
assertEquals(libDir.list().length, 0); assertEquals(libDir.list().length, 0);
assertTrue( assertTrue(LibraryLoaderHelper.loadNativeLibrariesUsingWorkaroundForTesting(
LibraryLoaderHelper.loadNativeLibrariesUsingWorkaroundForTesting(
context)); context));
assertTrue(libDir.list().length > 0); assertTrue(libDir.list().length > 0);
...@@ -47,7 +48,8 @@ public class LibraryLoaderHelperTest extends InstrumentationTestCase { ...@@ -47,7 +48,8 @@ public class LibraryLoaderHelperTest extends InstrumentationTestCase {
@Override @Override
public void tearDown() throws Exception { public void tearDown() throws Exception {
Context context = getInstrumentation().getTargetContext(); Context context = getInstrumentation().getTargetContext();
LibraryLoaderHelper.deleteWorkaroundLibrariesSynchronously(context); LibraryLoaderHelper.deleteLibrariesSynchronously(
context, LibraryLoaderHelper.PACKAGE_MANAGER_WORKAROUND_DIR);
super.tearDown(); super.tearDown();
} }
} }
...@@ -576,6 +576,28 @@ jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz, jlong bytes) { ...@@ -576,6 +576,28 @@ jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz, jlong bytes) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(address)); return static_cast<jlong>(reinterpret_cast<uintptr_t>(address));
} }
// Get the full path of a library in the zip file
// (lib/<abi>/crazy.<lib_name>).
//
// |env| is the current JNI environment handle.
// |clazz| is the static class handle which is not used here.
// |lib_name| is the library base name.
// Returns the full path (or empty string on failure).
jstring GetLibraryFilePathInZipFile(JNIEnv* env,
jclass clazz,
jstring lib_name) {
String lib_name_str(env, lib_name);
const char* lib_name_c_str = lib_name_str.c_str();
char buffer[kMaxFilePathLengthInZip + 1];
if (crazy_library_file_path_in_zip_file(
lib_name_c_str, buffer, sizeof(buffer)) == CRAZY_STATUS_FAILURE) {
LOG_ERROR("%s: Failed to get full filename for library '%s'",
__FUNCTION__, lib_name_c_str);
buffer[0] = '\0';
}
return env->NewStringUTF(buffer);
}
// Check whether the device supports loading a library directly from the APK // Check whether the device supports loading a library directly from the APK
// file. // file.
// //
...@@ -686,19 +708,25 @@ const JNINativeMethod kNativeMethods[] = { ...@@ -686,19 +708,25 @@ const JNINativeMethod kNativeMethods[] = {
")" ")"
"J", "J",
reinterpret_cast<void*>(&GetRandomBaseLoadAddress)}, reinterpret_cast<void*>(&GetRandomBaseLoadAddress)},
{"nativeCheckLibraryLoadFromApkSupport", {"nativeGetLibraryFilePathInZipFile",
"(" "("
"Ljava/lang/String;" "Ljava/lang/String;"
")" ")"
"Z", "Ljava/lang/String;",
reinterpret_cast<void*>(&CheckLibraryLoadFromApkSupport)}, reinterpret_cast<void*>(&GetLibraryFilePathInZipFile)},
{"nativeCheckLibraryAlignedInApk", {"nativeCheckLibraryLoadFromApkSupport",
"(" "("
"Ljava/lang/String;" "Ljava/lang/String;"
"Ljava/lang/String;" ")"
")" "Z",
"Z", reinterpret_cast<void*>(&CheckLibraryLoadFromApkSupport)},
reinterpret_cast<void*>(&CheckLibraryAlignedInApk)}, }; {"nativeCheckLibraryAlignedInApk",
"("
"Ljava/lang/String;"
"Ljava/lang/String;"
")"
"Z",
reinterpret_cast<void*>(&CheckLibraryAlignedInApk)}, };
} // namespace } // namespace
......
...@@ -32,6 +32,9 @@ extern "C" { ...@@ -32,6 +32,9 @@ extern "C" {
// the library. // the library.
#define _CRAZY_PUBLIC __attribute__((__visibility__("default"))) #define _CRAZY_PUBLIC __attribute__((__visibility__("default")))
// Maximum path length of a file in a zip file.
const size_t kMaxFilePathLengthInZip = 256;
// Status values returned by crazy linker functions to indicate // Status values returned by crazy linker functions to indicate
// success or failure. They were chosen to match boolean values, // success or failure. They were chosen to match boolean values,
// this allows one to test for failures with: // this allows one to test for failures with:
...@@ -335,6 +338,15 @@ crazy_status_t crazy_library_find_from_address( ...@@ -335,6 +338,15 @@ crazy_status_t crazy_library_find_from_address(
void* address, void* address,
crazy_library_t** library) _CRAZY_PUBLIC; crazy_library_t** library) _CRAZY_PUBLIC;
// Return the full path of |lib_name| in the zip file
// (lib/<abi>/crazy.<lib_name>). The result is returned in
// |buffer[0..buffer_size - 1]|. If |buffer_size| is too small,
// CRAZY_STATUS_FAILURE is returned.
crazy_status_t crazy_library_file_path_in_zip_file(const char* lib_name,
char* buffer,
size_t buffer_size)
_CRAZY_PUBLIC;
// Check whether |lib_name| is page aligned in |zipfile_name|. // Check whether |lib_name| is page aligned in |zipfile_name|.
crazy_status_t crazy_linker_check_library_aligned_in_zip_file( crazy_status_t crazy_linker_check_library_aligned_in_zip_file(
const char* zipfile_name, const char* zipfile_name,
......
...@@ -372,6 +372,20 @@ crazy_status_t crazy_library_find_from_address(void* address, ...@@ -372,6 +372,20 @@ crazy_status_t crazy_library_find_from_address(void* address,
} }
} }
crazy_status_t crazy_library_file_path_in_zip_file(const char* lib_name,
char* buffer,
size_t buffer_size) {
crazy::String path = crazy::LibraryList::GetLibraryFilePathInZipFile(
lib_name);
if (path.size() >= buffer_size) {
return CRAZY_STATUS_FAILURE;
}
memcpy(buffer, path.c_str(), path.size());
buffer[path.size()] = '\0';
return CRAZY_STATUS_SUCCESS;
}
crazy_status_t crazy_linker_check_library_aligned_in_zip_file( crazy_status_t crazy_linker_check_library_aligned_in_zip_file(
const char* zipfile_name, const char* zipfile_name,
const char* lib_name) { const char* lib_name) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "crazy_linker_library_list.h" #include "crazy_linker_library_list.h"
#include <assert.h> #include <assert.h>
#include <crazy_linker.h>
#include <dlfcn.h> #include <dlfcn.h>
#include "crazy_linker_debug.h" #include "crazy_linker_debug.h"
...@@ -20,9 +21,6 @@ namespace crazy { ...@@ -20,9 +21,6 @@ namespace crazy {
namespace { namespace {
// Maximum filename length of a file in a zip file.
const size_t kMaxFilenameInZip = 256;
// Page size for alignment in a zip file. // Page size for alignment in a zip file.
const size_t kZipAlignmentPageSize = 4096; const size_t kZipAlignmentPageSize = 4096;
static_assert(kZipAlignmentPageSize % PAGE_SIZE == 0, static_assert(kZipAlignmentPageSize % PAGE_SIZE == 0,
...@@ -401,24 +399,28 @@ LibraryView* LibraryList::LoadLibrary(const char* lib_name, ...@@ -401,24 +399,28 @@ LibraryView* LibraryList::LoadLibrary(const char* lib_name,
#error "Unsupported target abi" #error "Unsupported target abi"
#endif #endif
String LibraryList::GetLibraryFilePathInZipFile(const char* lib_name) {
String path;
path.Reserve(kMaxFilePathLengthInZip);
path = "lib/";
path += CURRENT_ABI;
path += "/crazy.";
path += lib_name;
return path;
}
int LibraryList::FindAlignedLibraryInZipFile( int LibraryList::FindAlignedLibraryInZipFile(
const char* zip_file_path, const char* zip_file_path,
const char* lib_name, const char* lib_name,
Error* error) { Error* error) {
String fullname; String path = GetLibraryFilePathInZipFile(lib_name);
fullname.Reserve(kMaxFilenameInZip); if (path.size() >= kMaxFilePathLengthInZip) {
fullname = "lib/";
fullname += CURRENT_ABI;
fullname += "/crazy.";
fullname += lib_name;
if (fullname.size() + 1 > kMaxFilenameInZip) {
error->Format("Filename too long for a file in a zip file %s\n", error->Format("Filename too long for a file in a zip file %s\n",
fullname.c_str()); path.c_str());
return CRAZY_OFFSET_FAILED; return CRAZY_OFFSET_FAILED;
} }
int offset = FindStartOffsetOfFileInZipFile(zip_file_path, fullname.c_str()); int offset = FindStartOffsetOfFileInZipFile(zip_file_path, path.c_str());
if (offset == CRAZY_OFFSET_FAILED) { if (offset == CRAZY_OFFSET_FAILED) {
return CRAZY_OFFSET_FAILED; return CRAZY_OFFSET_FAILED;
} }
......
...@@ -71,6 +71,10 @@ class LibraryList { ...@@ -71,6 +71,10 @@ class LibraryList {
SearchPathList* search_path_list, SearchPathList* search_path_list,
Error* error); Error* error);
// Return the full path of |lib_name| in the zip file
// (lib/<abi>/crazy.<lib_name>).
static String GetLibraryFilePathInZipFile(const char* lib_name);
// Find the location of a library in the zip file. If the name of the library // Find the location of a library in the zip file. If the name of the library
// is too long, an error occurs during the search or the library is not // is too long, an error occurs during the search or the library is not
// page aligned in the zip file, CRAZY_OFFSET_FAILED is returned. Otherwise, // page aligned in the zip file, CRAZY_OFFSET_FAILED is returned. Otherwise,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment