diff --git a/build.gradle b/build.gradle index 8989499..28f56a7 100755 --- a/build.gradle +++ b/build.gradle @@ -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' } diff --git a/relinker/src/main/java/com/getkeepsafe/relinker/ReLinker.java b/relinker/src/main/java/com/getkeepsafe/relinker/ReLinker.java index 95fa2d2..6cf7ef7 100755 --- a/relinker/src/main/java/com/getkeepsafe/relinker/ReLinker.java +++ b/relinker/src/main/java/com/getkeepsafe/relinker/ReLinker.java @@ -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) { @@ -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(); } diff --git a/relinker/src/main/java/com/getkeepsafe/relinker/ReLinkerInstance.java b/relinker/src/main/java/com/getkeepsafe/relinker/ReLinkerInstance.java index feb5233..1df7f8e 100755 --- a/relinker/src/main/java/com/getkeepsafe/relinker/ReLinkerInstance.java +++ b/relinker/src/main/java/com/getkeepsafe/relinker/ReLinkerInstance.java @@ -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. *

- * Note: This is a synchronous operation + * Note: This is a synchronous operation */ 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. + *

+ * Note: This is a synchronous operation + */ + 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. @@ -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, @@ -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) { @@ -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 dependencies; - try { - parser = new ElfParser(workaroundFile); - dependencies = parser.parseNeededDependencies(); - }finally { + final List 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); } /** @@ -237,8 +320,8 @@ protected File getWorkaroundLibFile(final Context context, * Cleans up any other 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. */