HeliBoard/app/src/main/java/helium314/keyboard/latin/utils/JniUtils.java

114 lines
5.5 KiB
Java
Raw Normal View History

2019-12-31 18:19:35 +01:00
/*
* Copyright (C) 2012 The Android Open Source Project
* modified
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
2019-12-31 18:19:35 +01:00
*/
package helium314.keyboard.latin.utils;
2019-12-31 18:19:35 +01:00
import android.annotation.SuppressLint;
import android.app.Application;
import android.os.Build;
import android.text.TextUtils;
2019-12-31 18:19:35 +01:00
import androidx.preference.PreferenceManager;
import helium314.keyboard.latin.App;
import helium314.keyboard.latin.BuildConfig;
import helium314.keyboard.latin.settings.Settings;
import java.io.File;
import java.io.FileInputStream;
2019-12-31 18:19:35 +01:00
public final class JniUtils {
private static final String TAG = JniUtils.class.getSimpleName();
public static final String JNI_LIB_NAME = "jni_latinime";
public static final String JNI_LIB_NAME_GOOGLE = "jni_latinimegoogle";
public static final String JNI_LIB_IMPORT_FILE_NAME = "libjni_latinime.so";
private static final String CHECKSUM_ARM64 = "b1049983e6ac5cfc6d1c66e38959751044fad213dff0637a6cf1d2a2703e754f";
private static final String CHECKSUM_ARM32 = "442a2a8bfcb25489564bc9433a916fa4dc0dba9000fe6f6f03f5939b985091e6";
private static final String CHECKSUM_X86_64 = "c882e12e6d48dd946e0b644c66868a720bd11ac3fecf152000e21a3d5abd59c9";
private static final String CHECKSUM_X86 = "bd946d126c957b5a6dea3bafa07fa36a27950b30e2b684dffc60746d0a1c7ad8";
public static String expectedDefaultChecksum() {
final String abi = Build.SUPPORTED_ABIS[0];
return switch (abi) {
case "arm64-v8a" -> CHECKSUM_ARM64;
case "armeabi-v7a" -> CHECKSUM_ARM32;
case "x86_64" -> CHECKSUM_X86_64;
case "x86" -> CHECKSUM_X86;
default -> "-"; // invalid checksum that definitely will not match
};
}
2019-12-31 18:19:35 +01:00
public static boolean sHaveGestureLib = false;
static {
// hardcoded default path, may not work on all phones
@SuppressLint("SdCardPath") String filesDir = "/data/data/" + BuildConfig.APPLICATION_ID + "/files";
Application app = App.Companion.getApp();
if (app == null) {
try {
// try using reflection to get (app)context: https://stackoverflow.com/a/38967293
// this may not be necessary any more, now that we get the app somewhere else?
app = (Application) Class.forName("android.app.ActivityThread")
.getMethod("currentApplication").invoke(null, (Object[]) null);
} catch (Exception ignored) { }
}
if (app != null) // use the actual path if possible
filesDir = app.getFilesDir().getAbsolutePath();
final File userSuppliedLibrary = new File(filesDir + File.separator + JNI_LIB_IMPORT_FILE_NAME);
if (!BuildConfig.BUILD_TYPE.equals("nouserlib") && userSuppliedLibrary.exists()) {
String wantedChecksum = expectedDefaultChecksum();
try {
if (app != null) {
// we want the default preferences, because storing the checksum in device protected storage is discouraged
// see https://developer.android.com/reference/android/content/Context#createDeviceProtectedStorageContext()
// if device is locked, this will throw an IllegalStateException
wantedChecksum = PreferenceManager.getDefaultSharedPreferences(app).getString(Settings.PREF_LIBRARY_CHECKSUM, wantedChecksum);
}
final String checksum = ChecksumCalculator.INSTANCE.checksum(new FileInputStream(userSuppliedLibrary));
if (TextUtils.equals(wantedChecksum, checksum)) {
// try loading the library
System.load(userSuppliedLibrary.getAbsolutePath());
sHaveGestureLib = true; // this is an assumption, any way to actually check?
} else {
// delete if checksum doesn't match
// this is bad if we can't get the application and the user has a different library than expected...
userSuppliedLibrary.delete();
sHaveGestureLib = false;
}
} catch (Throwable t) { // catch everything, maybe provided library simply doesn't work
if (!(t instanceof IllegalStateException) || !"SharedPreferences in credential encrypted storage are not available until after user is unlocked".equals(t.getMessage()))
// but don't log if device is locked, here we expect the exception and only load system library, if possible
Log.w(TAG, "Could not load user-supplied library", t);
}
}
if (!sHaveGestureLib) {
// try loading google library, will fail unless the library is in system and this is a system app
try {
System.loadLibrary(JNI_LIB_NAME_GOOGLE);
sHaveGestureLib = true;
} catch (UnsatisfiedLinkError ul) {
Log.w(TAG, "Could not load system glide typing library " + JNI_LIB_NAME_GOOGLE, ul);
}
}
if (!sHaveGestureLib) {
// try loading built-in library
try {
System.loadLibrary(JNI_LIB_NAME);
} catch (UnsatisfiedLinkError ul) {
Log.w(TAG, "Could not load native library " + JNI_LIB_NAME, ul);
}
2019-12-31 18:19:35 +01:00
}
}
private JniUtils() {
// This utility class is not publicly instantiable.
}
public static void loadNativeLibrary() {
// Ensures the static initializer is called
}
}