Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load library from the given path #58

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.android.tools.build:gradle:3.3.2'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4'
}
Expand Down
10 changes: 10 additions & 0 deletions relinker/src/main/java/com/getkeepsafe/relinker/ReLinker.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public static void loadLibrary(final Context context, final String library) {
loadLibrary(context, library, null, null);
}

public static void load(final Context context, final File library) {
load(context, library, null);
}

public static void loadLibrary(final Context context,
final String library,
final String version) {
Expand All @@ -70,6 +74,12 @@ public static void loadLibrary(final Context context,
new ReLinkerInstance().loadLibrary(context, library, version, listener);
}

public static void load(final Context context,
final File library,
final ReLinker.LoadListener listener) {
new ReLinkerInstance().recursively().load(context, library, listener); //no reason for not using recursively
}

public static ReLinkerInstance force() {
return new ReLinkerInstance().force();
}
Expand Down
125 changes: 104 additions & 21 deletions relinker/src/main/java/com/getkeepsafe/relinker/ReLinkerInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,22 @@ public ReLinkerInstance recursively() {
* Utilizes the regular system call to attempt to load a native library. If a failure occurs,
* then the function extracts native .so library out of the app's APK and attempts to load it.
* <p>
* <strong>Note: This is a synchronous operation</strong>
* <strong>Note: This is a synchronous operation</strong>
*/
public void loadLibrary(final Context context, final String library) {
loadLibrary(context, library, null, null);
}

/**
* Utilizes the regular system call to attempt to load a native library. If a failure occurs,
* then the function tries to load dependencies and then attempts to load it again.
* <p>
* <strong>Note: This is a synchronous operation</strong>
*/
public void load(final Context context, final File library) {
load(context, library, null);
}

/**
* The same call as {@link #loadLibrary(Context, String)}, however if a {@code version} is
* provided, then that specific version of the given library is loaded.
Expand All @@ -111,12 +121,12 @@ public void loadLibrary(final Context context,
}

/**
* Attemps to load the given library normally. If that fails, it loads the library utilizing
* Attempts to load the given library normally. If that fails, it loads the library utilizing
* a workaround.
*
* @param context The {@link Context} to get a workaround directory from
* @param library The library you wish to load
* @param version The version of the library you wish to load, or {@code null}
* @param context The {@link Context} to get a workaround directory from
* @param library The library you wish to load
* @param version The version of the library you wish to load, or {@code null}
* @param listener {@link ReLinker.LoadListener} to listen for async execution, or {@code null}
*/
public void loadLibrary(final Context context,
Expand Down Expand Up @@ -151,6 +161,45 @@ public void run() {
}
}

/**
* Attempts to load the given library normally. If that fails, it loads the library utilizing
* a workaround.
*
* @param context The {@link Context} to get a workaround directory from
* @param library The library file you wish to load
* @param listener {@link ReLinker.LoadListener} to listen for async execution, or {@code null}
*/
public void load(final Context context,
final File library,
final ReLinker.LoadListener listener) {
if (context == null) {
throw new IllegalArgumentException("Given context is null");
}

if (!library.exists()) {
throw new IllegalArgumentException("Given library file does not exists");
}

log("Beginning load of %s...", library);
if (listener == null) {
loadInternal(context, library);
} else {
new Thread(new Runnable() {
@Override
public void run() {
try {
loadInternal(context, library);
listener.success();
} catch (UnsatisfiedLinkError e) {
listener.failure(e);
} catch (MissingLibraryException e) {
listener.failure(e);
}
}
}).start();
}
}

private void loadLibraryInternal(final Context context,
final String library,
final String version) {
Expand Down Expand Up @@ -181,29 +230,63 @@ private void loadLibraryInternal(final Context context,
libraryLoader.mapLibraryName(library), workaroundFile, this);
}

if (recursive) {
loadDependencies(context, workaroundFile);
}

libraryLoader.loadPath(workaroundFile.getAbsolutePath());
loadedLibraries.add(library);
log("%s (%s) was re-linked!", library, version);
}

private void loadInternal(final Context context, final File library) {
String libraryPath = library.getAbsolutePath();
if (loadedLibraries.contains(libraryPath) && !force) {
log("%s already loaded previously!", libraryPath);
return;
}

try {
libraryLoader.loadPath(libraryPath);
loadedLibraries.add(libraryPath);
log("%s (%s) was loaded normally!", libraryPath);
return;
} catch (final UnsatisfiedLinkError e) {
// :-(
log("Loading the library normally failed: %s", Log.getStackTraceString(e));
}

log("%s (%s) was not loaded normally, re-linking...", libraryPath);

if (recursive) {
loadDependencies(context, library);
}

libraryLoader.loadPath(libraryPath);
loadedLibraries.add(libraryPath);
log("%s (%s) was re-linked!", libraryPath);
}

private void loadDependencies(final Context context, final File lib) {
try {
if (recursive) {
ElfParser parser = null;
final List<String> dependencies;
try {
parser = new ElfParser(workaroundFile);
dependencies = parser.parseNeededDependencies();
}finally {
final List<String> dependencies;
ElfParser parser = null;
try {
parser = new ElfParser(lib);
dependencies = parser.parseNeededDependencies();
} finally {
if (parser != null) {
parser.close();
}
for (final String dependency : dependencies) {
loadLibrary(context, libraryLoader.unmapLibraryName(dependency));
}
}
for (final String dependency : dependencies) {
loadLibrary(context, libraryLoader.unmapLibraryName(dependency));
}
} catch (IOException ignored) {
// This a redundant step of the process, if our library resolving fails, it will likely
// be picked up by the system's resolver, if not, an exception will be thrown by the
// next statement, so its better to try twice.
}

libraryLoader.loadPath(workaroundFile.getAbsolutePath());
loadedLibraries.add(library);
log("%s (%s) was re-linked!", library, version);
}

/**
Expand Down Expand Up @@ -237,8 +320,8 @@ protected File getWorkaroundLibFile(final Context context,
* Cleans up any <em>other</em> versions of the {@code library}. If {@code force} is used, all
* versions of the {@code library} are deleted
*
* @param context {@link Context} to retrieve the workaround directory from
* @param library The name of the library to load
* @param context {@link Context} to retrieve the workaround directory from
* @param library The name of the library to load
* @param currentVersion The version of the library to keep, all other versions will be deleted.
* This parameter is ignored if {@code force} is used.
*/
Expand Down