Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workaround[lwjgl]: Implement mitigation for an early EMUI linker hang. #5082

Merged
merged 1 commit into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;

@SuppressWarnings("IOStreamConstructor")
Expand Down Expand Up @@ -1093,6 +1094,23 @@ public static int mesureTextviewHeight(TextView t) {
return t.getMeasuredHeight();
}

/**
* Check if the device is one of the devices that may be affected by the hanging linker issue.
* The device is affected if the linker causes the process to lock up when dlopen() is called within
* dl_iterate_phdr().
* For now, the only affected firmware that I know of is Android 5.1, EMUI 3.1 on MTK-based Huawei
* devices.
* @return if the device is affected by the hanging linker issue.
*/
public static boolean deviceHasHangingLinker() {
// Android Oreo and onwards have GSIs and most phone firmwares at that point were not modified
// *that* intrusively. So assume that we are not affected.
if(SDK_INT >= Build.VERSION_CODES.O) return false;
// Since the affected function in LWJGL is rarely used (and when used, it's mainly for debug prints)
// we can make the search scope a bit more broad and check if we are running on a Huawei device.
return Build.MANUFACTURER.toLowerCase(Locale.ROOT).contains("huawei");
}

public static class RenderersList {
public final List<String> rendererIds;
public final String[] rendererDisplayNames;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ public static void setJavaEnvironment(Activity activity, String jreHome) throws
envMap.put("POJAV_ZINK_PREFER_SYSTEM_DRIVER", "1");
if(PREF_VSYNC_IN_ZINK)
envMap.put("POJAV_VSYNC_IN_ZINK", "1");
if(Tools.deviceHasHangingLinker())
envMap.put("POJAV_EMUI_ITERATOR_MITIGATE", "1");


// The OPEN GL version is changed according
Expand Down
38 changes: 38 additions & 0 deletions app_pojavlauncher/src/main/jni/input_bridge_v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
pojav_environ->mouseDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetDirectBufferAddress(pojav_environ->runtimeJNIEnvPtr_JRE, mouseDownBufferJ);
hookExec();
installLinkerBugMitigation();
installEMUIIteratorMititgation();
}

if(pojav_environ->dalvikJavaVMPtr == vm) {
Expand Down Expand Up @@ -294,6 +295,43 @@ void installLinkerBugMitigation() {
}
}

/**
* This function is meant as a substitute for SharedLibraryUtil.getLibraryPath() that just returns 0
* (thus making the parent Java function return null). This is done to avoid using the LWJGL's default function,
* which will hang the crappy EMUI linker by dlopen()ing inside of dl_iterate_phdr().
* @return 0, to make the parent Java function return null immediately.
* For reference: https://github.com/PojavLauncherTeam/lwjgl3/blob/fix_huawei_hang/modules/lwjgl/core/src/main/java/org/lwjgl/system/SharedLibraryUtil.java
*/
jint getLibraryPath_fix(__attribute__((unused)) JNIEnv *env,
__attribute__((unused)) jclass class,
__attribute__((unused)) jlong pLibAddress,
__attribute__((unused)) jlong sOutAddress,
__attribute__((unused)) jint bufSize){
return 0;
}

/**
* Install the linker hang mitigation that is meant to prevent linker hangs on old EMUI firmware.
*/
void installEMUIIteratorMititgation() {
if(getenv("POJAV_EMUI_ITERATOR_MITIGATE") == NULL) return;
__android_log_print(ANDROID_LOG_INFO, "EMUIIteratorFix", "Installing...");
JNIEnv* env = pojav_environ->runtimeJNIEnvPtr_JRE;
jclass sharedLibraryUtil = (*env)->FindClass(env, "org/lwjgl/system/SharedLibraryUtil");
if(sharedLibraryUtil == NULL) {
__android_log_print(ANDROID_LOG_ERROR, "EMUIIteratorFix", "Failed to find the target class");
(*env)->ExceptionClear(env);
return;
}
JNINativeMethod getLibraryPathMethod[] = {
{"getLibraryPath", "(JJI)I", &getLibraryPath_fix}
};
if((*env)->RegisterNatives(env, sharedLibraryUtil, getLibraryPathMethod, 1) != 0) {
__android_log_print(ANDROID_LOG_ERROR, "EMUIIteratorFix", "Failed to register the mitigation method");
(*env)->ExceptionClear(env);
}
}

void critical_set_stackqueue(jboolean use_input_stack_queue) {
pojav_environ->isUseStackQueueCall = (int) use_input_stack_queue;
}
Expand Down
1 change: 1 addition & 0 deletions app_pojavlauncher/src/main/jni/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ jstring convertStringJVM(JNIEnv* srcEnv, JNIEnv* dstEnv, jstring srcStr);

void hookExec();
void installLinkerBugMitigation();
void installEMUIIteratorMititgation();
JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, jclass clazz, jint action, jbyteArray copySrc);

Loading