Skip to content

Commit

Permalink
load library from the given path
Browse files Browse the repository at this point in the history
  • Loading branch information
artyomd committed Mar 8, 2019
1 parent 4a0ad08 commit 3e9d723
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 23 deletions.
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
127 changes: 105 additions & 22 deletions relinker/src/main/java/com/getkeepsafe/relinker/ReLinkerInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down 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 {
if (recursive) {
ElfParser parser = null;
final List<String> dependencies;
try {
parser = new ElfParser(workaroundFile);
dependencies = parser.parseNeededDependencies();
}finally {
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 {
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

0 comments on commit 3e9d723

Please sign in to comment.