From 334274c9e596e93343451d71498c07532f39c145 Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Tue, 6 Jun 2023 22:08:00 +0200 Subject: [PATCH] auto extract native libraries and detect lib name for NativeActivity --- README.md | 8 ------ src/api-impl/android/app/NativeActivity.java | 30 ++++++++++++++++++++ src/main-executable/main.c | 16 +++++++++++ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index be5a6d81..f465fc39 100644 --- a/README.md +++ b/README.md @@ -29,14 +29,6 @@ or just `android-translation-layer [path to apk] -l [activity to launch]` to use the default data dir of `~/.local/share/android_translation_layer/` -NOTE: for apps which use the built-in NativeActivity mechanism, simply specify `-l android/app/NativeActivity` -if `android.app.lib_name` is set in the manifest, you currently need to rename the lib to `libmain.so`, which is the default. -in cases where there's alread a different lib with that name, you need to add a way to pass the lib name to the NativeActivity class -if `android.app.func_name` is set in the manifest, then you need to add a way to pass this to the NativeActivity class -(currently, the default of `ANativeActivity_onCreate` is always used, which works for all apps using `android_native_app_glue`) -TODO: figure out a mechanism for passing these to the NativeActivity class -TODO_LONGTERM: parse AndroidManifest.xml - NOTE: some apps don't like runtime changes to resolution, and currently GLSurfaceView will stretch instead of changing resolution to sidestep this, we allow for specifying the initial resolution, which will currently always get passed as the screen resolution to the app and to GLSurfaceView even when you resize the window. example with custom width/height: `android-translation-layer path/to/org.happysanta.gd_29.apk -l org/happysanta/gd/GDActivity -w 540 -h 960` diff --git a/src/api-impl/android/app/NativeActivity.java b/src/api-impl/android/app/NativeActivity.java index 83599844..36bd8fbb 100644 --- a/src/api-impl/android/app/NativeActivity.java +++ b/src/api-impl/android/app/NativeActivity.java @@ -37,6 +37,12 @@ import android.view.WindowManager; //import android.view.inputmethod.InputMethodManager; import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; +import com.reandroid.arsc.chunk.xml.ResXmlAttribute; +import com.reandroid.arsc.chunk.xml.ResXmlElement; /** * Convenience for implementing an activity that will be implemented @@ -161,6 +167,30 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback, throw new RuntimeException("Error getting activity info", e); }*/ + // parse AndroidManifest.xml to get name and entry of native lib + try (InputStream inStream = ClassLoader.getSystemClassLoader().getResourceAsStream("AndroidManifest.xml")) { + for (ResXmlElement activity: AndroidManifestBlock.load(inStream).listActivities()) { + if (!getClass().getName().equals(activity.searchAttributeByResourceId(AndroidManifestBlock.ID_name).getValueAsString())) { + continue; + } + for (ResXmlElement metaData: activity.listElements(AndroidManifestBlock.TAG_meta_data)) { + ResXmlAttribute name = metaData.searchAttributeByResourceId(AndroidManifestBlock.ID_name); + ResXmlAttribute value = metaData.searchAttributeByResourceId(AndroidManifestBlock.ID_value); + if (name == null || value == null){ + continue; + } + if (META_DATA_LIB_NAME.equals(name.getValueAsString())){ + libname = value.getValueAsString(); + } + if (META_DATA_FUNC_NAME.equals(name.getValueAsString())){ + funcname = value.getValueAsString(); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + } + String path = null; File libraryFile = new File(new File(android.os.Environment.getExternalStorageDirectory(), "lib"), diff --git a/src/main-executable/main.c b/src/main-executable/main.c index 4db7e566..055e56f4 100644 --- a/src/main-executable/main.c +++ b/src/main-executable/main.c @@ -16,6 +16,18 @@ #define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)/* 0666*/ #endif +#ifdef __x86_64__ +#define NATIVE_ARCH "x86_64" +#elifdef __i386__ +#define NATIVE_ARCH "x86" +#elifdef __aarch64__ +#define NATIVE_ARCH "arm64-v8a" +#elifdef __arm__ +#define NATIVE_ARCH "armeabi-v7a" +#else +#error unknown native architecture +#endif + GtkWidget *window; // standard Gtk Application stuff, more or less @@ -272,6 +284,8 @@ static void open(GtkApplication *app, GFile** files, gint nfiles, const gchar* h char *app_lib_dir = malloc(strlen(app_data_dir) + strlen("/lib") + 1); // +1 for NULL strcpy(app_lib_dir, app_data_dir); strcat(app_lib_dir, "/lib"); + // create lib dir + mkdir(app_lib_dir, DEFFILEMODE | S_IXUSR | S_IXGRP | S_IXOTH); // calling directly into the shim bionic linker to whitelist the app's lib dir as containing bionic-linked libraries dl_parse_library_path(app_lib_dir, ":"); @@ -326,6 +340,8 @@ static void open(GtkApplication *app, GFile** files, gint nfiles, const gchar* h (*env)->CallVoidMethod(env, java_runtime, loadLibrary_with_classloader, _JSTRING("translation_layer_main"), class_loader); extract_from_apk("assets/", "assets/"); + /* extract native libraries from apk*/ + extract_from_apk("lib/" NATIVE_ARCH "/", "lib/"); /* -- run the main activity's onCreate -- */