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

Zink, but swapchain-based #4246

Open
wants to merge 1 commit into
base: v3_openjdk
Choose a base branch
from
Open
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
17 changes: 16 additions & 1 deletion app_pojavlauncher/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,24 @@ LOCAL_SRC_FILES := \
environ/environ.c \
input_bridge_v3.c \
jre_launcher.c \
utils.c
utils.c \
driver_helper/nsbypass.c
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
LOCAL_CFLAGS += -DADRENO_POSSIBLE
LOCAL_LDLIBS += -lEGL -lGLESv2
endif
include $(BUILD_SHARED_LIBRARY)

#ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
include $(CLEAR_VARS)
LOCAL_MODULE := linkerhook
LOCAL_SRC_FILES := driver_helper/hook.c
LOCAL_LDLIBS := -llog
LOCAL_LDFLAGS := -z global
include $(BUILD_SHARED_LIBRARY)
#endif


include $(CLEAR_VARS)
LOCAL_MODULE := istdio
LOCAL_SHARED_LIBRARIES := xhook
Expand Down
2 changes: 1 addition & 1 deletion app_pojavlauncher/src/main/jni/Application.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# NDK_TOOLCHAIN_VERSION := 4.9
APP_PLATFORM := android-21
APP_STL := system
APP_STL := c++_static
# APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
11 changes: 9 additions & 2 deletions app_pojavlauncher/src/main/jni/ctxbridges/osmesa_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@
#include <stdlib.h>
#include <dlfcn.h>
#include "osmesa_loader.h"

#include <android/log.h>
GLboolean (*OSMesaMakeCurrent_p) (OSMesaContext ctx, void *buffer, GLenum type,
GLsizei width, GLsizei height);
OSMesaContext (*OSMesaGetCurrentContext_p) (void);
OSMesaContext (*OSMesaCreateContext_p) (GLenum format, OSMesaContext sharelist);
void (*OSMesaDestroyContext_p) (OSMesaContext ctx);
void (*OSMesaFlushFrontbuffer_p) ();
void (*OSMesaPixelStore_p) ( GLint pname, GLint value );
GLubyte* (*glGetString_p) (GLenum name);
void (*glFinish_p) (void);
void (*glClearColor_p) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
void (*glClear_p) (GLbitfield mask);
void (*glReadPixels_p) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data);
void (*glReadBuffer_p) (GLenum mode);

void dlsym_OSMesa() {
char* main_path = NULL;
Expand All @@ -28,15 +30,20 @@ void dlsym_OSMesa() {
void* dl_handle = NULL;
dl_handle = dlopen(alt_path, RTLD_GLOBAL);
if(dl_handle == NULL) dl_handle = dlopen(main_path, RTLD_GLOBAL);
if(dl_handle == NULL) abort();
if(dl_handle == NULL) {
__android_log_print(ANDROID_LOG_INFO, "osmesa_loader", "failed to load OSMesa %s", dlerror());
abort();
}
OSMesaMakeCurrent_p = dlsym(dl_handle, "OSMesaMakeCurrent");
OSMesaGetCurrentContext_p = dlsym(dl_handle,"OSMesaGetCurrentContext");
OSMesaCreateContext_p = dlsym(dl_handle, "OSMesaCreateContext");
OSMesaDestroyContext_p = dlsym(dl_handle, "OSMesaDestroyContext");
OSMesaFlushFrontbuffer_p = dlsym(dl_handle, "OSMesaFlushFrontbuffer");
OSMesaPixelStore_p = dlsym(dl_handle,"OSMesaPixelStore");
glGetString_p = dlsym(dl_handle,"glGetString");
glClearColor_p = dlsym(dl_handle, "glClearColor");
glClear_p = dlsym(dl_handle,"glClear");
glFinish_p = dlsym(dl_handle,"glFinish");
glReadPixels_p = dlsym(dl_handle,"glReadPixels");
glReadBuffer_p = dlsym(dl_handle, "glReadBuffer");
}
2 changes: 2 additions & 0 deletions app_pojavlauncher/src/main/jni/ctxbridges/osmesa_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ extern GLboolean (*OSMesaMakeCurrent_p) (OSMesaContext ctx, void *buffer, GLenum
extern OSMesaContext (*OSMesaGetCurrentContext_p) (void);
extern OSMesaContext (*OSMesaCreateContext_p) (GLenum format, OSMesaContext sharelist);
extern void (*OSMesaDestroyContext_p) (OSMesaContext ctx);
extern void (*OSMesaFlushFrontbuffer_p) ();
extern void (*OSMesaPixelStore_p) ( GLint pname, GLint value );
extern GLubyte* (*glGetString_p) (GLenum name);
extern void (*glFinish_p) (void);
extern void (*glClearColor_p) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
extern void (*glClear_p) (GLbitfield mask);
extern void (*glReadPixels_p) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data);
extern void (*glReadBuffer_p) (GLenum mode);
void dlsym_OSMesa();
#endif //POJAVLAUNCHER_OSMESA_LOADER_H
43 changes: 43 additions & 0 deletions app_pojavlauncher/src/main/jni/driver_helper/hook.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Created by maks on 05.06.2023.
//
#include <android/dlext.h>
#include <android/log.h>
#include <string.h>

typedef void* (*android_dlopen_ext_t)(const char *filename, int flags, const android_dlextinfo *extinfo);
typedef struct android_namespace_t* (*android_get_exported_namespace_t)(const char* name);

static void* ready_handle;
static android_dlopen_ext_t original_func;
static android_get_exported_namespace_t android_get_exported_namespace;

static const char *sphal_namespaces[3] = {
"sphal", "vendor", "default"
};


__attribute__((visibility("default"))) void app__pojav_linkerhook_set_data(void* data, void* data1, void* data2) {
ready_handle = data;
original_func = data1;
android_get_exported_namespace = data2;
}

__attribute__((visibility("default"))) void *android_dlopen_ext(const char *filename, int flags, const android_dlextinfo *extinfo) {
if(!strstr(filename, "vulkan."))
return original_func(filename, flags, extinfo);
return ready_handle;
}

__attribute__((visibility("default"))) void *android_load_sphal_library(const char *filename, int flags) {
if(strstr(filename, "vulkan.")) return ready_handle;
struct android_namespace_t* androidNamespace;
for(int i = 0; i < 3; i++) {
androidNamespace = android_get_exported_namespace(sphal_namespaces[i]);
if(androidNamespace != NULL) break;
}
android_dlextinfo info;
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
info.library_namespace = androidNamespace;
return original_func(filename, flags, &info);
}
164 changes: 164 additions & 0 deletions app_pojavlauncher/src/main/jni/driver_helper/nsbypass.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
//
// Created by maks on 05.06.2023.
//
#include "nsbypass.h"
#include <dlfcn.h>
#include <android/dlext.h>
#include <android/log.h>
#include <sys/mman.h>
#include <sys/user.h>
#include <string.h>
#include <stdio.h>
#include <linux/limits.h>
#include <errno.h>
#include <unistd.h>
#include <asm/unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <elf.h>

/* upper 6 bits of an ARM64 instruction are the instruction name */
#define OP_MS 0b11111100000000000000000000000000
/* Branch Label instruction opcode and immediate mask */
#define BL_OP 0b10010100000000000000000000000000
#define BL_IM 0b00000011111111111111111111111111
/* Library search path */
#define SEARCH_PATH "/system/lib64"
#define ELF_EHDR Elf64_Ehdr
#define ELF_SHDR Elf64_Shdr
#define ELF_HALF Elf64_Half
#define ELF_XWORD Elf64_Xword
#define ELF_DYN Elf64_Dyn

//#define ADRENO_POSSIBLE

typedef void* (*loader_dlopen_t)(const char* filename, int flags, const void* caller_addr);

typedef struct android_namespace_t* (*ld_android_create_namespace_t)(
const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
const char* permitted_when_isolated_path, struct android_namespace_t* parent, const void* caller_addr);

typedef struct android_namespace_t* (*ld_android_get_exported_namespace_t)(const char* name, const void* caller_addr);

static ld_android_create_namespace_t android_create_namespace;
static ld_android_get_exported_namespace_t android_get_exported_namespace;
static struct android_namespace_t* namespace;

struct android_namespace_t* local_android_create_namespace(
const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
const char* permitted_when_isolated_path, struct android_namespace_t* parent) {
void* caller = __builtin_return_address(0);
return android_create_namespace(name, ld_library_path, default_library_path, type, permitted_when_isolated_path, parent, caller);
}

struct android_namespace_t* ns_android_get_exported_namespace(
const char* name) {
void* caller = __builtin_return_address(0);
return android_get_exported_namespace(name, caller);
}


bool linker_ns_load(const char* lib_search_path) {
#ifndef ADRENO_POSSIBLE
return false;
#endif
uint32_t *dlext_bl_addr = (uint32_t*)&dlopen;
while((*dlext_bl_addr & OP_MS) !=
BL_OP) dlext_bl_addr++; //walk through the function until we find the label that we need to go to
__android_log_print(ANDROID_LOG_INFO, "nsbypass", "found branch label: %u", *dlext_bl_addr);
loader_dlopen_t loader_dlopen;
loader_dlopen = (loader_dlopen_t)(((char *) dlext_bl_addr) + (*dlext_bl_addr & BL_IM)*4);
mprotect(loader_dlopen, PAGE_SIZE, PROT_WRITE | PROT_READ | PROT_EXEC); // reprotecting the function removes protection from indirect jumps
void* ld_android_handle = loader_dlopen("ld-android.so", RTLD_LAZY, &dlopen);
__android_log_print(ANDROID_LOG_INFO, "nsbypass", "ld-android.so handle: %p", ld_android_handle);
if(ld_android_handle == NULL) return false;
android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace");
android_get_exported_namespace = dlsym(ld_android_handle, "__loader_android_get_exported_namespace");
if(android_create_namespace == NULL || android_get_exported_namespace == NULL) {
dlclose(ld_android_handle);
return false;
}
char full_path[strlen(SEARCH_PATH) + strlen(lib_search_path) + 2 + 1];
sprintf(full_path, "%s:%s", SEARCH_PATH, lib_search_path);
namespace = local_android_create_namespace("pojav-driver",
full_path,
full_path,
3 /* TYPE_SHAFED | TYPE_ISOLATED */,
"/system/:/data/:/vendor/:/apex/", NULL);
return true;
}

void* linker_ns_dlopen(const char* name, int flag) {
#ifndef ADRENO_POSSIBLE
return NULL;
#endif
android_dlextinfo dlextinfo;
dlextinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
dlextinfo.library_namespace = namespace;
return android_dlopen_ext(name, flag, &dlextinfo);
}

bool patch_elf_soname(int patchfd, int realfd, uint16_t patchid) {
struct stat realstat;
if(fstat(realfd, &realstat)) return false;
if(ftruncate(patchfd, realstat.st_size) == -1) return false;
char* target = mmap(NULL, realstat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, patchfd, 0);
if(!target) return false;
if(read(realfd, target, realstat.st_size) != realstat.st_size) {
munmap(target, realstat.st_size);
return false;
}
close(realfd);


ELF_EHDR *ehdr = (ELF_EHDR*)target;
ELF_SHDR *shdr = (ELF_SHDR*)(target + ehdr->e_shoff);
for(ELF_HALF i = 0; i < ehdr->e_shnum; i++) {
ELF_SHDR *hdr = &shdr[i];
if(hdr->sh_type == SHT_DYNAMIC) {
char* strtab = target + shdr[hdr->sh_link].sh_offset;
ELF_DYN *dynEntries = (ELF_DYN*)(target + hdr->sh_offset);
for(ELF_XWORD k = 0; k < (hdr->sh_size / hdr->sh_entsize);k++) {
ELF_DYN* dynEntry = &dynEntries[k];
if(dynEntry->d_tag == DT_SONAME) {
char* soname = strtab + dynEntry->d_un.d_val;
char sprb[4];
snprintf(sprb, 4, "%03x", patchid);
memcpy(soname, sprb, 3);
munmap(target, realstat.st_size);
return true;
}
}
}
}
return false;
}

void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flags) {
#ifndef ADRENO_POSSIBLE
return NULL;
#endif
char pathbuf[PATH_MAX];
static uint16_t patch_id;
int patch_fd, real_fd;
snprintf(pathbuf,PATH_MAX,"%s/%d_p.so", tmpdir, patch_id);
patch_fd = open(pathbuf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if(patch_fd == -1) return NULL;
snprintf(pathbuf,PATH_MAX,"%s/%s", SEARCH_PATH, name);
real_fd = open(pathbuf, O_RDONLY);
if(real_fd == -1) {
close(patch_fd);
return NULL;
}
if(!patch_elf_soname(patch_fd, real_fd, patch_id)) {
close(patch_fd);
close(real_fd);
return NULL;
}
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE | ANDROID_DLEXT_USE_LIBRARY_FD;
extinfo.library_fd = patch_fd;
extinfo.library_namespace = namespace;
snprintf(pathbuf, PATH_MAX, "/proc/self/fd/%d", patch_fd);
return android_dlopen_ext(pathbuf, flags, &extinfo);
}
15 changes: 15 additions & 0 deletions app_pojavlauncher/src/main/jni/driver_helper/nsbypass.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// Created by maks on 05.06.2023.
//

#ifndef POJAVLAUNCHER_NSBYPASS_H
#define POJAVLAUNCHER_NSBYPASS_H

#include <stdbool.h>

bool linker_ns_load(const char* lib_search_path);
void* linker_ns_dlopen(const char* name, int flag);
void* linker_ns_dlopen_unique(const char* tmpdir, const char* name, int flag);
struct android_namespace_t* ns_android_get_exported_namespace(const char*);

#endif //POJAVLAUNCHER_NSBYPASS_H
Loading