From 71268636df5965823038ca0df3d0c5d5a0dc54da Mon Sep 17 00:00:00 2001 From: Cory McWilliams Date: Sun, 30 Jun 2024 13:32:17 -0400 Subject: [PATCH] Steps toward following all the inconvenient, changing android rules: * Set android:debuggable=false. * Call native code through JNI only. Having a native executable on disk and exec-ing it no longer seems possible. * Do all the Tilde Friends things in one process, without a proper sandbox, until I can wire up a restricted service worker process. * Jam Android App Bundle (.aab) building into the makefile. * Yuck. --- GNUmakefile | 70 +++++++++++++--- src/android/AndroidManifest.xml | 5 +- src/android/BundleConfig.json | 5 ++ .../tildefriends/TildeFriendsActivity.java | 32 +++++--- src/main.c | 81 +++++++++++++++++++ 5 files changed, 166 insertions(+), 27 deletions(-) create mode 100644 src/android/BundleConfig.json diff --git a/GNUmakefile b/GNUmakefile index cec46f60..34d5ec7c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -3,12 +3,13 @@ MAKEFLAGS += --warn-undefined-variables MAKEFLAGS += --no-builtin-rules -VERSION_CODE := 21 +VERSION_CODE := 22 VERSION_NUMBER := 0.0.21-wip VERSION_NAME := Psst. Look behind you. SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460000.zip LIBUV_URL := https://dist.libuv.org/dist/v1.48.0/libuv-v1.48.0.tar.gz +BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar PROJECT = tildefriends BUILD_DIR ?= out @@ -16,6 +17,7 @@ UNAME_S := $(shell uname -s) UNAME_M := $(shell uname -m) ANDROID_SDK ?= ~/Android/Sdk +BUNDLETOOL = out/bundletool.jar HAVE_WIN := 0 @@ -150,9 +152,10 @@ ANDROID_RELEASE_TARGETS := $(filter-out $(DEBUG_TARGETS),$(ANDROID_TARGETS)) NONANDROID_RELEASE_TARGETS := $(filter-out $(ANDROID_ARM64_TARGETS),$(RELEASE_TARGETS)) NONANDROID_TARGETS := $(filter-out $(ANDROID_TARGETS),$(ALL_TARGETS)) NONMACOS_TARGETS := $(filter-out $(MACOS_TARGETS) $(IOS_TARGETS) $(IOSSIM_TARGETS),$(ALL_TARGETS)) +DEADSTRIP_TARGETS := $(filter-out $(ANDROID_TARGETS),$(NONMACOS_TARGETS)) $(NONANDROID_TARGETS): CFLAGS += -fno-omit-frame-pointer -$(filter-out $(ANDROID_TARGETS) $(WINDOWS_TARGETS),$(ALL_TARGETS)): LDFLAGS += -rdynamic +$(filter-out $(WINDOWS_TARGETS),$(ALL_TARGETS)): LDFLAGS += -rdynamic $(ANDROID_TARGETS): CFLAGS += \ --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot \ -fPIC \ @@ -205,7 +208,7 @@ $(ANDROID_X86_TARGETS): LDFLAGS += -Ldeps/openssl/android/x86/usr/local/lib $(ANDROID_X86_64_TARGETS): CFLAGS += -Ideps/openssl/android/x86_64/usr/local/include $(ANDROID_X86_64_TARGETS): LDFLAGS += -Ldeps/openssl/android/x86_64/usr/local/lib $(NONMACOS_TARGETS): CFLAGS += -Wno-cast-function-type -$(NONMACOS_TARGETS): LDFLAGS += -Wl,--gc-sections +$(DEADSTRIP_TARGETS): LDFLAGS += -Wl,--gc-sections $(IOS_TARGETS): CFLAGS += -mios-version-min=9.0 -Ideps/openssl/ios/ios64-xcrun/usr/local/include $(IOS_TARGETS): LDFLAGS += -Ldeps/openssl/ios/ios64-xcrun/usr/local/lib $(IOSSIM_TARGETS): CFLAGS += -Ideps/openssl/ios/iossimulator-xcrun/usr/local/include @@ -698,7 +701,7 @@ $(CLASS_FILES) &: $(JAVA_FILES) out/apk/classes.dex: $(CLASS_FILES) @mkdir -p $(dir $@) @echo "[d8] $@" - @$(ANDROID_BUILD_TOOLS)/d8 --$(BUILD_TYPE) --lib $(ANDROID_PLATFORM)/android.jar --output $(dir $@) out/classes/com/unprompted/tildefriends/*.class + @$(ANDROID_BUILD_TOOLS)/d8 --lib $(ANDROID_PLATFORM)/android.jar --output $(dir $@) out/classes/com/unprompted/tildefriends/*.class PACKAGE_DIRS := \ apps/ \ @@ -719,13 +722,51 @@ out/apk/TildeFriends-arm-release.unsigned.apk: out/apk/classes.dex out/androidre out/apk/TildeFriends-x86-debug.unsigned.apk: out/apk/classes.dex out/androiddebug-x86_64/tildefriends out/androiddebug-x86/tildefriends $(RAW_FILES) out/apk/res.apk out/apk/TildeFriends-x86-release.unsigned.apk: out/apk/classes.dex out/androidrelease-x86_64/tildefriends out/androidrelease-x86/tildefriends $(RAW_FILES) out/apk/res.apk +$(BUNDLETOOL): + @echo [curl] $(BUNDLETOOL_URL) TO $@ + @curl -q -L --create-dirs -o $@ $(BUNDLETOOL_URL) + +out/TildeFriends.aab: out/apk/classes.dex $(filter-out %debug%, $(ANDROID_TARGETS)) $(RAW_FILES) out/apk/res.apk src/android/AndroidManifest.xml $(BUNDLETOOL) + @rm -rf out/aab/staging/ + @mkdir -p out/aab/staging + @$(ANDROID_BUILD_TOOLS)/aapt2 link --proto-format -o out/aab/temporary.apk -I $(ANDROID_PLATFORM)/android.jar --manifest src/android/AndroidManifest.xml -R out/res/layout_activity_main.xml.flat -R out/res/drawable_icon.xml.flat --auto-add-overlay + @unzip out/aab/temporary.apk -d out/aab/staging/ + @mkdir -p out/aab/staging/root/deps + @mkdir -p out/aab/staging/classes + @mkdir -p out/aab/staging/dex + @mkdir -p out/aab/staging/manifest + @mv out/aab/staging/AndroidManifest.xml out/aab/staging/manifest/AndroidManifest.xml + @cp out/apk/classes.dex out/aab/staging/dex/ + @rm -fv out/base.zip + @cp -r out/apk-arm-release/lib/ out/aab/staging/ + @cp -r out/apk-x86-release/lib/ out/aab/staging/ + @cp -r apps/ out/aab/staging/root/ + @rm -rf out/aab/staging/root/apps/welcome* + @cp -r core/ out/aab/staging/root/ + @cp -r deps/prettier/ out/aab/staging/root/deps/ + @cp -r deps/lit/ out/aab/staging/root/deps/ + @cp -r deps/codemirror/ out/aab/staging/root/deps/ + @cd out/aab/staging/; zip -r ../base.zip *; cd ../../../ + @java -jar $(BUNDLETOOL) build-bundle --overwrite --config=src/android/BundleConfig.json --modules=out/aab/base.zip --output=$@ + @jarsigner -keystore .keys/android.jks $@ androidKey -storepass android + +aab: out/TildeFriends.aab +.PHONY: aab + +out/TildeFriends.apks: out/TildeFriends.aab $(BUNDLETOOL) + @java -jar $(BUNDLETOOL) build-apks --bundle out/TildeFriends.aab --overwrite --output $@ --ks .keys/android.jks --ks-key-alias androidKey --ks-pass pass:android + +aabgo: out/TildeFriends.apks $(BUNDLETOOL) + @java -jar $(BUNDLETOOL) install-apks --apks out/TildeFriends.apks + @adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity + out/apk/TildeFriends-arm-%.unsigned.apk: @mkdir -p $(dir $@) out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/ out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/ @echo "[aapt] $@" - @cp out/android$(BUILD_TYPE)/tildefriends out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/tildefriends.so - @cp out/android$(BUILD_TYPE)-armv7a/tildefriends out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/tildefriends.so - @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/tildefriends.so - @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/tildefriends.so + @cp out/android$(BUILD_TYPE)/tildefriends out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/libtildefriends.so + @cp out/android$(BUILD_TYPE)-armv7a/tildefriends out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/libtildefriends.so + @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-arm-$(BUILD_TYPE)/lib/arm64-v8a/libtildefriends.so + @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-arm-$(BUILD_TYPE)/lib/armeabi-v7a/libtildefriends.so @cp out/apk/res.apk $@.zip @cp out/apk/classes.dex out/apk-arm-$(BUILD_TYPE)/ @cd out/apk-arm-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../ @@ -735,10 +776,10 @@ out/apk/TildeFriends-arm-%.unsigned.apk: out/apk/TildeFriends-x86-%.unsigned.apk: @mkdir -p $(dir $@) out/apk-x86-$(BUILD_TYPE)/lib/x86_64/ out/apk-x86-$(BUILD_TYPE)/lib/x86/ @echo "[aapt] $@" - @cp out/android$(BUILD_TYPE)-x86_64/tildefriends out/apk-x86-$(BUILD_TYPE)/lib/x86_64/tildefriends.so - @cp out/android$(BUILD_TYPE)-x86/tildefriends out/apk-x86-$(BUILD_TYPE)/lib/x86/tildefriends.so - @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-x86-$(BUILD_TYPE)/lib/x86_64/tildefriends.so - @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-x86-$(BUILD_TYPE)/lib/x86/tildefriends.so + @cp out/android$(BUILD_TYPE)-x86_64/tildefriends out/apk-x86-$(BUILD_TYPE)/lib/x86_64/libtildefriends.so + @cp out/android$(BUILD_TYPE)-x86/tildefriends out/apk-x86-$(BUILD_TYPE)/lib/x86/libtildefriends.so + @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-x86-$(BUILD_TYPE)/lib/x86_64/libtildefriends.so + @$(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip out/apk-x86-$(BUILD_TYPE)/lib/x86/libtildefriends.so @cp out/apk/res.apk $@.zip @cp out/apk/classes.dex out/apk-x86-$(BUILD_TYPE)/ @cd out/apk-x86-$(BUILD_TYPE) && zip -u ../../$@.zip -q -9 -r . && cd ../../ @@ -757,6 +798,11 @@ out/%.zopfli.apk: out/%.apk release-apk: out/TildeFriends-arm-release.zopfli.apk out/TildeFriends-x86-release.zopfli.apk .PHONY: release-apk +apkgo: out/TildeFriends-arm-debug.apk + @adb install -r $< + @adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity +.PHONY: apkgo + releaseapkgo: out/TildeFriends-arm-release.apk @adb install -r $< @adb shell am start com.unprompted.tildefriends/.TildeFriendsActivity diff --git a/src/android/AndroidManifest.xml b/src/android/AndroidManifest.xml index 0280ca8d..c3a6ef34 100644 --- a/src/android/AndroidManifest.xml +++ b/src/android/AndroidManifest.xml @@ -1,15 +1,14 @@ + android:debuggable="false"> upload_message; private final static int FILECHOOSER_RESULT = 1; private float touch_down_y; + static { + Log.w("tildefriends", "Calling system.loadLibrary()."); + System.loadLibrary("tildefriends"); + Log.w("tildefriends", "system.loadLibrary() completed."); + } + + static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path); + @Override protected void onCreate(Bundle savedInstanceState) { StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() @@ -76,7 +86,7 @@ public class TildeFriendsActivity extends Activity { Log.w("tildefriends", String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString())); Log.w("tildefriends", String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir)); - String port_file_path = getFilesDir().toString() + "/port.txt"; + port_file_path = getFilesDir().toString() + "/port.txt"; new File(port_file_path).delete(); base_url = "http://127.0.0.1:12345/"; @@ -134,17 +144,15 @@ public class TildeFriendsActivity extends Activity { thread.start(); set_status("Starting server..."); - String exe = getApplicationInfo().nativeLibraryDir + "/tildefriends.so"; - ProcessBuilder builder = new ProcessBuilder(exe, "run", "-z", getPackageResourcePath().toString(), "-a", "out_http_port_file=" + port_file_path, "-p", "0"); - Log.w("tildefriends", "files = " + getFilesDir().toString()); - Log.w("tildefriends", "exe = " + exe); - builder.directory(getFilesDir()); - builder.inheritIO(); - try { - process = builder.start(); - } catch (java.io.IOException e) { - Log.w("tildefriends", "IOException starting process: " + e.toString()); - } + server_thread = new Thread(new Runnable() { + @Override + public void run() { + Log.w("tildefriends", "Calling tf_server_main."); + int result = tf_server_main(getFilesDir().toString(), getPackageResourcePath().toString(), port_file_path); + Log.w("tildefriends", "tf_server_main returned " + result + "."); + } + }); + server_thread.start(); web_view.getSettings().setJavaScriptEnabled(true); web_view.getSettings().setDatabaseEnabled(true); diff --git a/src/main.c b/src/main.c index 09df8e6c..e834383b 100644 --- a/src/main.c +++ b/src/main.c @@ -34,6 +34,10 @@ #include #endif +#if defined(__ANDROID__) +#include "jni.h" +#endif + #if !defined(_countof) #define _countof(a) ((int)(sizeof((a)) / sizeof(*(a)))) #endif @@ -726,6 +730,83 @@ static void _startup(int argc, char* argv[]) } #if defined(__ANDROID__) +static jint _tf_server_main(JNIEnv* env, jobject this_object, jstring files_dir, jstring apk_path, jstring out_port_file_path) +{ + tf_printf("This is tf_server_main main.\n"); + _startup(0, (char*[]) { NULL }); + tf_printf("That was startup.\n"); + + const char* files = (*env)->GetStringUTFChars(env, files_dir, NULL); + const char* apk = (*env)->GetStringUTFChars(env, apk_path, NULL); + const char* out_port_file = (*env)->GetStringUTFChars(env, out_port_file_path, NULL); + + tf_printf("FILES = %s\n", files); + tf_printf("APK = %s\n", apk); + tf_printf("OUT_PORT = %s\n", out_port_file); + + int result = uv_chdir(files); + if (result) + { + tf_printf("uv_chdir: %s\n", uv_strerror(result)); + } + + size_t port_file_arg_length = strlen(out_port_file) + strlen("out_http_port_file=") + 1; + char* port_file_arg = alloca(port_file_arg_length); + snprintf(port_file_arg, port_file_arg_length, "out_http_port_file=%s", out_port_file); + + const char* args[] = + { + "-z", + apk, + "-a", + port_file_arg, + "-p", + "0", + "-o", /* HACK! FIXME! */ + }; + + result = _tf_command_run(apk, _countof(args), (char**)args); + + (*env)->ReleaseStringUTFChars(env, files_dir, files); + (*env)->ReleaseStringUTFChars(env, apk_path, apk); + (*env)->ReleaseStringUTFChars(env, out_port_file_path, out_port_file); + + tf_printf("tf_server_main finished with %d.", result); + return result; +} + +JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + tf_printf("JNI_Onload called.\n"); + JNIEnv* env; + if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) + { + tf_printf("Failed to get JNI environment.\n"); + return JNI_ERR; + } + + tf_printf("Finding class.\n"); + jclass c = (*env)->FindClass(env, "com/unprompted/tildefriends/TildeFriendsActivity"); + if (!c) + { + tf_printf("Failed to find TildeFriendsActivity class.\n"); + return JNI_ERR; + } + + tf_printf("Registering method.\n"); + static const JNINativeMethod methods[] = { + { "tf_server_main", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", _tf_server_main }, + }; + int result = (*env)->RegisterNatives(env, c, methods, (int)_countof(methods)); + if (result != JNI_OK) + { + return result; + } + + tf_printf("Done.\n"); + return JNI_VERSION_1_6; +} + int main(int argc, char* argv[]) { _startup(argc, argv);