Repository navigation
Expand file tree
/
Copy pathvulkan_loader.c
More file actions
122 lines (102 loc) · 4.37 KB
/
Copy pathvulkan_loader.c
File metadata and controls
122 lines (102 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//
// Created by maks on 10.04.2026.
//
#include <android/api-level.h>
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <jni.h>
#include <driver_helper/nsbypass.h>
#include <android/dlext.h>
#include <mojoexec.h>
#include <string.h>
#include "paths.h"
#include "utils.h"
static char* driver_lib = NULL;
static char* driver_path = NULL;
#ifdef ENABLE_VULKAN_OVERRIDE
static bool load_vulkan_driver() {
static bool driver_loaded = false;
if(driver_lib == NULL) {
printf("MojoExec: attempted to preload custom driver, yet no driver is specified\n");
return false;
}
if(driver_loaded) return true;
const char* cache_dir = getenv("TMPDIR");
// The hooked vulkan loader will always be put into the primary mojoexec namespace
struct android_namespace_t *main_ns = get_primary_namespace();
if(!main_ns) {
printf("MojoExec: failed to load main namespace!\n");
return NULL;
}
// By default, the driver will use the primary namespace which includes launcher libs. However,
// to avoid 3rd party driver packages from loading launcher libs (and possibly failing),
// we allow the user to specify custom search paths. This will create another namespace,
// completely isolated from the launcher.
struct android_namespace_t *driver_ns = main_ns;
if(driver_path != NULL) {
driver_ns = linker_ns_load(driver_path, "mojoexec-driver");
}
void* linkerhook = linker_ns_dlopen(main_ns, "liblinkerhook.so", RTLD_LOCAL | RTLD_NOW);
if(linkerhook == NULL) {
printf("MojoExec: failed to load linkerhook! %s\n", dlerror());
return NULL;
}
void* driver_handle = linker_ns_dlopen(driver_ns, driver_lib, RTLD_LOCAL | RTLD_NOW);
if(driver_handle == NULL) {
printf("MojoExec: Failed to load custom Vulkan driver (%s)!\n%s\n", driver_lib, dlerror());
goto fail_l;
} else printf("MojoExec: Loaded Vulkan library : %p\n", driver_handle);
void* dl_android = linker_ns_dlopen(main_ns, "libdl_android.so", RTLD_LOCAL | RTLD_LAZY);
if(dl_android == NULL) {
printf("MojoExec: failed to dlopen dl_android! %s\n", dlerror());
goto fail_t;
}
void* android_get_exported_namespace = dlsym(dl_android, "android_get_exported_namespace");
void (*linkerhook_pass_handles)(void*, void*, void*) = dlsym(linkerhook, "app__pojav_linkerhook_pass_handles");
if(linkerhook_pass_handles == NULL || android_get_exported_namespace == NULL) goto fail_d;
linkerhook_pass_handles(driver_handle, android_dlopen_ext, android_get_exported_namespace);
void* libvulkan = linker_ns_dlopen_unique(main_ns, cache_dir, "libvulkan.so", "libmjlvlk.so", RTLD_LOCAL | RTLD_NOW);
if(libvulkan) {
printf("MojoExec: Loaded mjlvlk, ptr=%p\n", libvulkan);
driver_loaded = true;
return true;
} else {
printf("MojoExec: failed to reference mjlvlk, %s\n", dlerror());
}
fail_d: dlclose(dl_android);
fail_t: dlclose(driver_handle);
fail_l: dlclose(linkerhook);
return false;
}
#endif
void* mojoexec_acq_vulkan_handle() {
int flags = RTLD_LOCAL | RTLD_NOW;
#ifdef ENABLE_VULKAN_OVERRIDE
if(android_get_device_api_level() >= 28) { // the loader does not support below that
if(driver_lib != NULL && load_vulkan_driver())
// Reference the vulkan driver separately to avoid weirdness from libraries calling dlclose
return linker_ns_dlopen(get_primary_namespace(), "libmjlvlk.so", flags);
}
#endif
void* vulkan_ptr = dlopen("libvulkan.so", flags);
printf("MojoExec: loaded system vulkan, ptr=%p\n", vulkan_ptr);
return vulkan_ptr;
}
// Does nothing if Turnip is unsupported - Mesa will load system driver automatically
JNIEXPORT void JNICALL
Java_git_artdeell_mojoexec_MojoExec_preloadVulkan(JNIEnv *env, jclass clazz) {
#ifdef ENABLE_VULKAN_OVERRIDE
if(driver_lib == NULL) return;
if(!load_vulkan_driver()) {
printf("MojoExec: Failed to preload Vulkan driver!\n");
}
#endif
}
JNIEXPORT void JNICALL
Java_git_artdeell_mojoexec_MojoExec_configureCustomVulkanDriver(JNIEnv *env, jclass clazz,
jstring library_name,
jstring library_search_path) {
save_jvm_string(env, &driver_lib, library_name);
save_jvm_string(env, &driver_path, library_search_path);
}