mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-18 09:07:48 -04:00
Fix[ffmpeg_plugin]: replace LD_LIBRARY_PATH/PATH for ffmpeg, switch default exec mode
This commit is contained in:
parent
041838725b
commit
6d39ab2d49
@ -368,7 +368,8 @@ public class JREUtils {
|
|||||||
|
|
||||||
"-Dnet.minecraft.clientmodname=" + Tools.APP_NAME,
|
"-Dnet.minecraft.clientmodname=" + Tools.APP_NAME,
|
||||||
"-Dfml.earlyprogresswindow=false", //Forge 1.14+ workaround
|
"-Dfml.earlyprogresswindow=false", //Forge 1.14+ workaround
|
||||||
"-Dloader.disable_forked_guis=true"
|
"-Dloader.disable_forked_guis=true",
|
||||||
|
"-Djdk.lang.Process.launchMechanism=FORK" // Default is POSIX_SPAWN which requires starting jspawnhelper, which doesn't work on Android
|
||||||
));
|
));
|
||||||
if(LauncherPreferences.PREF_ARC_CAPES) {
|
if(LauncherPreferences.PREF_ARC_CAPES) {
|
||||||
overridableArguments.add("-javaagent:"+new File(Tools.DIR_DATA,"arc_dns_injector/arc_dns_injector.jar").getAbsolutePath()+"=23.95.137.176");
|
overridableArguments.add("-javaagent:"+new File(Tools.DIR_DATA,"arc_dns_injector/arc_dns_injector.jar").getAbsolutePath()+"=23.95.137.176");
|
||||||
|
@ -45,6 +45,7 @@ LOCAL_SRC_FILES := \
|
|||||||
jre_launcher.c \
|
jre_launcher.c \
|
||||||
utils.c \
|
utils.c \
|
||||||
stdio_is.c \
|
stdio_is.c \
|
||||||
|
java_exec_hooks.c \
|
||||||
driver_helper/nsbypass.c
|
driver_helper/nsbypass.c
|
||||||
|
|
||||||
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
#define EVENT_TYPE_MOUSE_BUTTON 1006
|
#define EVENT_TYPE_MOUSE_BUTTON 1006
|
||||||
#define EVENT_TYPE_SCROLL 1007
|
#define EVENT_TYPE_SCROLL 1007
|
||||||
|
|
||||||
jint (*orig_ProcessImpl_forkAndExec)(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream);
|
|
||||||
|
|
||||||
static void registerFunctions(JNIEnv *env);
|
static void registerFunctions(JNIEnv *env);
|
||||||
|
|
||||||
jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
|
jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
|
||||||
@ -230,56 +228,6 @@ void sendData(int type, int i1, int i2, int i3, int i4) {
|
|||||||
atomic_fetch_add_explicit(&pojav_environ->eventCounter, 1, memory_order_acquire);
|
atomic_fetch_add_explicit(&pojav_environ->eventCounter, 1, memory_order_acquire);
|
||||||
}
|
}
|
||||||
|
|
||||||
static jbyteArray stringToBytes(JNIEnv *env, const char* string) {
|
|
||||||
const jsize string_data_len = (jsize)(strlen(string) + 1);
|
|
||||||
jbyteArray result = (*env)->NewByteArray(env, (jsize)string_data_len);
|
|
||||||
(*env)->SetByteArrayRegion(env, result, 0, (jsize)string_data_len, (const jbyte*) string);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hooked version of java.lang.UNIXProcess.forkAndExec()
|
|
||||||
* which is used to handle the "open" command and "ffmpeg" invocations
|
|
||||||
*/
|
|
||||||
jint
|
|
||||||
hooked_ProcessImpl_forkAndExec(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream) {
|
|
||||||
const char *pProg = (char *)((*env)->GetByteArrayElements(env, prog, NULL));
|
|
||||||
const char* pProgBaseName = basename(pProg);
|
|
||||||
const size_t basename_len = strlen(pProgBaseName);
|
|
||||||
char prog_basename[basename_len];
|
|
||||||
memcpy(&prog_basename, pProgBaseName, basename_len + 1);
|
|
||||||
(*env)->ReleaseByteArrayElements(env, prog, (jbyte *)pProg, 0);
|
|
||||||
|
|
||||||
if(strcmp(prog_basename, "xdg-open") == 0) {
|
|
||||||
// When invoking xdg-open, send that open command into the android half instead
|
|
||||||
Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(env, NULL, /* CLIPBOARD_OPEN */ 2002, argBlock);
|
|
||||||
return 0;
|
|
||||||
}else if(strcmp(prog_basename, "ffmpeg") == 0) {
|
|
||||||
// When invoking ffmpeg, always replace the program path with the path to ffmpeg from the plugin.
|
|
||||||
const char* ffmpeg_path = getenv("POJAV_FFMPEG_PATH");
|
|
||||||
if(ffmpeg_path != NULL) {
|
|
||||||
prog = stringToBytes(env, ffmpeg_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return orig_ProcessImpl_forkAndExec(env, process, mode, helperpath, prog, argBlock, argc, envBlock, envc, dir, std_fds, redirectErrorStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void hookExec() {
|
|
||||||
jclass cls;
|
|
||||||
orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_UNIXProcess_forkAndExec");
|
|
||||||
if (!orig_ProcessImpl_forkAndExec) {
|
|
||||||
orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_ProcessImpl_forkAndExec");
|
|
||||||
cls = (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "java/lang/ProcessImpl");
|
|
||||||
} else {
|
|
||||||
cls = (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "java/lang/UNIXProcess");
|
|
||||||
}
|
|
||||||
JNINativeMethod methods[] = {
|
|
||||||
{"forkAndExec", "(I[B[B[BI[BI[B[IZ)I", (void *)&hooked_ProcessImpl_forkAndExec}
|
|
||||||
};
|
|
||||||
(*pojav_environ->runtimeJNIEnvPtr_JRE)->RegisterNatives(pojav_environ->runtimeJNIEnvPtr_JRE, cls, methods, 1);
|
|
||||||
printf("Registered forkAndExec\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basically a verbatim implementation of ndlopen(), found at
|
* Basically a verbatim implementation of ndlopen(), found at
|
||||||
* https://github.com/PojavLauncherTeam/lwjgl3/blob/3.3.1/modules/lwjgl/core/src/generated/c/linux/org_lwjgl_system_linux_DynamicLinkLoader.c#L11
|
* https://github.com/PojavLauncherTeam/lwjgl3/blob/3.3.1/modules/lwjgl/core/src/generated/c/linux/org_lwjgl_system_linux_DynamicLinkLoader.c#L11
|
||||||
|
90
app_pojavlauncher/src/main/jni/java_exec_hooks.c
Normal file
90
app_pojavlauncher/src/main/jni/java_exec_hooks.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
//
|
||||||
|
// Created by maks on 05.01.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <environ/environ.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <utils.h>
|
||||||
|
|
||||||
|
static jint (*orig_ProcessImpl_forkAndExec)(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream);
|
||||||
|
|
||||||
|
// Turn a C-style string into a Java byte array
|
||||||
|
static jbyteArray stringToBytes(JNIEnv *env, const char* string) {
|
||||||
|
const jsize string_data_len = (jsize)(strlen(string) + 1);
|
||||||
|
jbyteArray result = (*env)->NewByteArray(env, (jsize)string_data_len);
|
||||||
|
(*env)->SetByteArrayRegion(env, result, 0, (jsize)string_data_len, (const jbyte*) string);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace the env block with the one that has the desired LD_LIBRARY_PATH/PATH.
|
||||||
|
// (Due to my laziness this ignores the current contents of the block)
|
||||||
|
static void replaceLibPathInEnvBlock(JNIEnv *env, jbyteArray* envBlock, jint* envc, const char* directory) {
|
||||||
|
static bool env_block_replacement_warning = false;
|
||||||
|
if(*envBlock != NULL && !env_block_replacement_warning) {
|
||||||
|
printf("exec_hooks WARN: replaceLibPathInEnvBlock does not preserve original env. Please notify PojavLauncherTeam if you need that feature\n");
|
||||||
|
env_block_replacement_warning = true;
|
||||||
|
}
|
||||||
|
char envStr[1024];
|
||||||
|
jsize new_envl = snprintf(envStr, sizeof(envStr) / sizeof(char), "LD_LIBRARY_PATH=%s%cPATH=%s", directory, 0 ,directory) + 1;
|
||||||
|
jbyteArray newBlock = (*env)->NewByteArray(env, new_envl);
|
||||||
|
(*env)->SetByteArrayRegion(env, newBlock, 0, new_envl, (jbyte*) envStr);
|
||||||
|
*envBlock = newBlock;
|
||||||
|
*envc = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooked version of java.lang.UNIXProcess.forkAndExec()
|
||||||
|
* which is used to handle the "open" command and "ffmpeg" invocations
|
||||||
|
*/
|
||||||
|
static jint hooked_ProcessImpl_forkAndExec(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream) {
|
||||||
|
const char *pProg = (char *)((*env)->GetByteArrayElements(env, prog, NULL));
|
||||||
|
const char* pProgBaseName = basename(pProg);
|
||||||
|
const size_t basename_len = strlen(pProgBaseName);
|
||||||
|
char prog_basename[basename_len];
|
||||||
|
memcpy(&prog_basename, pProgBaseName, basename_len + 1);
|
||||||
|
(*env)->ReleaseByteArrayElements(env, prog, (jbyte *)pProg, 0);
|
||||||
|
|
||||||
|
if(strcmp(prog_basename, "xdg-open") == 0) {
|
||||||
|
// When invoking xdg-open, send the open URL into Android
|
||||||
|
Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(env, NULL, /* CLIPBOARD_OPEN */ 2002, argBlock);
|
||||||
|
return 0;
|
||||||
|
}else if(strcmp(prog_basename, "ffmpeg") == 0) {
|
||||||
|
// When invoking ffmpeg, always replace the program path with the path to ffmpeg from the plugin.
|
||||||
|
// This allows us to replace the executable name, which is needed because android doesn't allow
|
||||||
|
// us to put files that don't start with "lib" and end with ".so" into folders that we can execute
|
||||||
|
// from
|
||||||
|
|
||||||
|
// Also add LD_LIBRARY_PATH and PATH for the lib in order to override the ones from the launcher, since
|
||||||
|
// they may interfere with ffmpeg dependencies.
|
||||||
|
const char* ffmpeg_path = getenv("POJAV_FFMPEG_PATH");
|
||||||
|
prog = NULL;
|
||||||
|
if(ffmpeg_path != NULL) {
|
||||||
|
replaceLibPathInEnvBlock(env, &envBlock, &envc, dirname(ffmpeg_path));
|
||||||
|
prog = stringToBytes(env, ffmpeg_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orig_ProcessImpl_forkAndExec(env, process, mode, helperpath, prog, argBlock, argc, envBlock, envc, dir, std_fds, redirectErrorStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook the forkAndExec method in the Java runtime for custom executable overriding.
|
||||||
|
void hookExec() {
|
||||||
|
jclass cls;
|
||||||
|
orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_UNIXProcess_forkAndExec");
|
||||||
|
if (!orig_ProcessImpl_forkAndExec) {
|
||||||
|
orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_ProcessImpl_forkAndExec");
|
||||||
|
cls = (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "java/lang/ProcessImpl");
|
||||||
|
} else {
|
||||||
|
cls = (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "java/lang/UNIXProcess");
|
||||||
|
}
|
||||||
|
JNINativeMethod methods[] = {
|
||||||
|
{"forkAndExec", "(I[B[B[BI[BI[B[IZ)I", (void *)&hooked_ProcessImpl_forkAndExec}
|
||||||
|
};
|
||||||
|
(*pojav_environ->runtimeJNIEnvPtr_JRE)->RegisterNatives(pojav_environ->runtimeJNIEnvPtr_JRE, cls, methods, 1);
|
||||||
|
printf("Registered forkAndExec\n");
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user