Skip to content

Commit

Permalink
replace library load with native code
Browse files Browse the repository at this point in the history
  • Loading branch information
qimiko committed Dec 22, 2023
1 parent 989e96f commit bad9a59
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 20 deletions.
4 changes: 3 additions & 1 deletion app/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ if(NOT dobby_POPULATED)
add_subdirectory("${dobby_SOURCE_DIR}" ${dobby_BINARY_DIR} EXCLUDE_FROM_ALL)
target_include_directories(launcherfix PRIVATE ${dobby_SOURCE_DIR}/include)
target_link_libraries(launcherfix dobby)
endif()
endif()

target_link_libraries(launcherfix log)
39 changes: 38 additions & 1 deletion app/src/main/cpp/launcher-fix.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include <android/dlext.h>
#include <android/log.h>
#include <dlfcn.h>
#include <string>
#include <jni.h>
#include <string>
#include <unistd.h>

#ifndef DISABLE_LAUNCHER_FIX
#include <dobby.h>
Expand Down Expand Up @@ -30,6 +33,8 @@ JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setDataPath(
auto data_path_str = env->GetStringUTFChars(data_path, &is_copy);

DataPaths::get_instance().data_path = std::string(data_path_str);

env->ReleaseStringUTFChars(data_path, data_path_str);
}

extern "C"
Expand All @@ -42,6 +47,38 @@ JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setOriginalDataPath(
auto data_path_str = env->GetStringUTFChars(data_path, &is_copy);

DataPaths::get_instance().original_data_path = std::string(data_path_str);

env->ReleaseStringUTFChars(data_path, data_path_str);
}

extern "C"
JNIEXPORT jboolean JNICALL Java_com_geode_launcher_LauncherFix_loadLibraryFromOffset(JNIEnv *env, jobject, jstring library_name, jint fd, jlong offset) {
// loads a given library at an offset and file descriptor
// assumes we have ownership of the file passed in fd

auto is_copy = jboolean();
auto library_cname = env->GetStringUTFChars(library_name, &is_copy);

android_dlextinfo ext_info{};
ext_info.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET;
ext_info.library_fd = fd;
ext_info.library_fd_offset = offset;

auto handle = android_dlopen_ext(library_cname, RTLD_NOW | RTLD_GLOBAL, &ext_info);
env->ReleaseStringUTFChars(library_name, library_cname);
close(fd);

if (handle == nullptr) {
auto error = dlerror();
__android_log_print(ANDROID_LOG_WARN, "GeodeLauncher-Fix", "dlopen_ext failed. given: %s\n", error);

return false;
}

// we don't need the library anymore
dlclose(handle);

return true;
}

FILE* (*fopen_original)(const char *pathname, const char *mode);
Expand Down
29 changes: 11 additions & 18 deletions app/src/main/java/com/geode/launcher/GeometryDashActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,9 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
}
}

@SuppressLint("UnsafeDynamicallyLoadedCode")
private fun loadLibraryFromAssets(libraryName: String) {
// loads a library loaded in assets
// this currently requires copying the library to a non-compressed directory
// ideally a better solution would be found, but i'm out of ideas

val libraryCopy = File(cacheDir, "lib$libraryName.so")
if (libraryCopy.exists()) {
// don't force a copy on each load
// (you will have to clear cache if the library updates, so maybe remove this check)
System.load(libraryCopy.path)
return
}
// loads a library loaded in assets (which points to the apk + an offset)
// these libraries are available to the application after merging

// find the first instance of the library in preferred abi order
val libraryFd = Build.SUPPORTED_ABIS.asSequence()
Expand All @@ -148,14 +138,17 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
}
.firstOrNull() ?: throw UnsatisfiedLinkError("Could not find library lib$libraryName.so")

// copy the library to a path we can access
// there doesn't seem to be a way to load a library from a file descriptor
val libraryOutput = libraryCopy.outputStream()
copyFile(libraryFd.createInputStream(), libraryOutput)
val fdOffset = libraryFd.startOffset
val fdDescriptor = libraryFd.parcelFileDescriptor.detachFd()

System.load(libraryCopy.path)
if (!LauncherFix.loadLibraryFromOffset("lib$libraryName.so", fdDescriptor, fdOffset)) {
throw UnsatisfiedLinkError("Failed to load asset lib$libraryName.so")
}

return
// after the library is opened in native code, it should be available for loading
// you can read more about the behavior:
// https://android.googlesource.com/platform/libcore/+/7f3eb2e0ac87bdea471bc577380cf50025aebde5/ojluni/src/main/java/java/lang/Runtime.java#1060
System.loadLibrary(libraryName)
}

@SuppressLint("UnsafeDynamicallyLoadedCode")
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/geode/launcher/LauncherFix.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ object LauncherFix {
external fun setDataPath(dataPath: String)

external fun setOriginalDataPath(dataPath: String)

external fun loadLibraryFromOffset(libraryName: String, fd: Int, offset: Long): Boolean
}

0 comments on commit bad9a59

Please sign in to comment.