Improve JNI loading efficiency (#1224)

A hash is stored for each native library with the name libraryName.hash.
If the library is not found on the system search path, it is extracted to a cache directory.
Extracted libraries are named with the hash appended, so the library will not be
re-extracted if one with the same hash already exists.

Hashing without the hash file requires double traversing if the file is not in the cache,
but it is still faster than creating a new file in most cases.  This won't be needed
after opencv is updated to provide a hash as well.
This commit is contained in:
Thad House
2018-07-29 10:20:41 -07:00
committed by Peter Johnson
parent cbb62fb98f
commit 00c2cd7dab
7 changed files with 214 additions and 171 deletions

View File

@@ -7,63 +7,28 @@
package edu.wpi.first.wpilibj.hal;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import edu.wpi.first.wpiutil.RuntimeDetector;
import edu.wpi.first.wpiutil.RuntimeLoader;
/**
* Base class for all JNI wrappers.
*/
public class JNIWrapper {
static boolean libraryLoaded = false;
static File jniLibrary = null;
static RuntimeLoader<JNIWrapper> loader = null;
static {
if (!libraryLoaded) {
String jniFileName = "wpiHal";
try {
System.loadLibrary(jniFileName);
} catch (UnsatisfiedLinkError ule) {
try {
String resname = RuntimeDetector.getLibraryResource(jniFileName);
InputStream is = JNIWrapper.class.getResourceAsStream(resname);
if (is != null) {
// create temporary file
if (System.getProperty("os.name").startsWith("Windows")) {
jniLibrary = File.createTempFile(jniFileName, ".dll");
} else if (System.getProperty("os.name").startsWith("Mac")) {
jniLibrary = File.createTempFile(jniFileName, ".dylib");
} else {
jniLibrary = File.createTempFile(jniFileName, ".so");
}
// flag for delete on exit
jniLibrary.deleteOnExit();
OutputStream os = new FileOutputStream(jniLibrary);
byte[] buffer = new byte[1024];
int readBytes;
try {
while ((readBytes = is.read(buffer)) != -1) {
os.write(buffer, 0, readBytes);
}
} finally {
os.close();
is.close();
}
System.load(jniLibrary.getAbsolutePath());
} else {
System.loadLibrary(jniFileName);
}
} catch (IOException ex) {
ex.printStackTrace();
System.exit(1);
}
loader = new RuntimeLoader<>("wpiHal", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class);
loader.loadLibrary();
} catch (IOException ex) {
ex.printStackTrace();
System.exit(1);
}
libraryLoaded = true;
libraryLoaded = true;
}
}
}