Commit a0c53668e6a85e59c4a80a3b4e8c95e78cd6e2e5

Sam Lantinga 2018-10-04T16:29:17

Allow SDL to use ReLinker if present. This fixes issues for applications that have a large number of shared libraries For more information, see https://github.com/KeepSafe/ReLinker for ReLinker's repository.

diff --git a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java
index bd9de19..0ab2269 100644
--- a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java
+++ b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java
@@ -577,7 +577,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         }
 
         // We need to skip the first byte, as that doesn't go over the air
-	byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
+        byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
         //Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(actual_report));
         writeCharacteristic(reportCharacteristic, actual_report);
         return report.length;
diff --git a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
index 33ddb71..ba30d0a 100644
--- a/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
+++ b/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
@@ -80,14 +80,14 @@ public class HIDDeviceManager {
     public HIDDeviceManager(Context context) {
         mContext = context;
 
-	// Make sure we have the HIDAPI library loaded with the native functions
+        // Make sure we have the HIDAPI library loaded with the native functions
         try {
-            System.loadLibrary("hidapi");
+            SDL.loadLibrary("hidapi");
         } catch (Exception e) {
             Log.w(TAG, "Couldn't load hidapi: " + e.toString());
             return;
         }
-	
+
         HIDDeviceRegisterCallback(this);
 
         mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDL.java b/android-project/app/src/main/java/org/libsdl/app/SDL.java
index cfe4830..58597c6 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDL.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDL.java
@@ -2,6 +2,8 @@ package org.libsdl.app;
 
 import android.content.Context;
 
+import java.lang.reflect.*;
+
 /**
     SDL library initialization
 */
@@ -33,5 +35,50 @@ public class SDL {
         return mContext;
     }
 
+    public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
+
+        if (libraryName == null) {
+            throw new NullPointerException("No library name provided.");
+        }
+
+        try {
+            // Let's see if we have ReLinker available in the project.  This is necessary for 
+            // some projects that have huge numbers of local libraries bundled, and thus may 
+            // trip a bug in Android's native library loader which ReLinker works around.  (If
+            // loadLibrary works properly, ReLinker will simply use the normal Android method
+            // internally.)
+            //
+            // To use ReLinker, just add it as a dependency.  For more information, see 
+            // https://github.com/KeepSafe/ReLinker for ReLinker's repository.
+            //
+            Class relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
+            Class relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
+            Class contextClass = mContext.getClassLoader().loadClass("android.content.Context");
+            Class stringClass = mContext.getClassLoader().loadClass("java.lang.String");
+
+            // Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if 
+            // they've changed during updates.
+            Method forceMethod = relinkClass.getDeclaredMethod("force");
+            Object relinkInstance = forceMethod.invoke(null);
+            Class relinkInstanceClass = relinkInstance.getClass();
+
+            // Actually load the library!
+            Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass);
+            loadMethod.invoke(relinkInstance, mContext, libraryName, null, null);
+        }
+        catch (final Exception e) {
+            // Fall back
+            try {
+                System.loadLibrary(libraryName);
+            }
+            catch (final UnsatisfiedLinkError ule) {
+                throw ule;
+            }
+            catch (final SecurityException se) {
+                throw se;
+            }
+        }        
+    }
+
     protected static Context mContext;
 }
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
index c53970f..67cb3a3 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
@@ -154,7 +154,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     // Load the .so
     public void loadLibraries() {
        for (String lib : getLibraries()) {
-          System.loadLibrary(lib);
+          SDL.loadLibrary(lib);
        }
     }