diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 4eee7de198..bd7c0dbdb7 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -30,8 +30,8 @@ android { minSdk = 26 targetSdk = 36 - versionCode = 4 - versionName = "1.0.3" + versionCode = 5 + versionName = "1.0.4" ndk { abiFilters += listOf("arm64-v8a") diff --git a/android/app/src/main/cpp/android_crash_handler.cpp b/android/app/src/main/cpp/android_crash_handler.cpp index 32c6e9d463..3c4191923f 100644 --- a/android/app/src/main/cpp/android_crash_handler.cpp +++ b/android/app/src/main/cpp/android_crash_handler.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -9,6 +10,9 @@ namespace { constexpr const char* kCrashTag = "xemu-android"; +constexpr size_t kPathMax = 512; + +static char g_inline_aio_flag_path[kPathMax]; static int GetTid() { return static_cast(syscall(SYS_gettid)); @@ -53,9 +57,28 @@ static void LogBacktrace() { } } +static void MarkInlineAioRequired() { + if (g_inline_aio_flag_path[0] == '\0') { + return; + } + + int fd = open(g_inline_aio_flag_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) { + return; + } + + static const char kValue[] = "1\n"; + ssize_t ignored = write(fd, kValue, sizeof(kValue) - 1); + (void)ignored; + close(fd); +} + static void CrashHandler(int sig, siginfo_t* info, void* ucontext) { (void)info; (void)ucontext; + if (sig == SIGILL) { + MarkInlineAioRequired(); + } __android_log_print(ANDROID_LOG_ERROR, kCrashTag, "Caught signal %d in tid %d", sig, GetTid()); LogBacktrace(); @@ -69,10 +92,22 @@ static void InstallCrashHandlers() { sa.sa_sigaction = CrashHandler; sa.sa_flags = SA_SIGINFO | SA_RESETHAND; sigaction(SIGABRT, &sa, nullptr); + sigaction(SIGILL, &sa, nullptr); sigaction(SIGSEGV, &sa, nullptr); } } // namespace +extern "C" void xemu_android_set_inline_aio_crash_flag_path(const char* path) { + if (!path) { + g_inline_aio_flag_path[0] = '\0'; + return; + } + + size_t len = strnlen(path, sizeof(g_inline_aio_flag_path) - 1); + memcpy(g_inline_aio_flag_path, path, len); + g_inline_aio_flag_path[len] = '\0'; +} + __attribute__((constructor)) static void InstallCrashHandlersOnLoad() { InstallCrashHandlers(); } diff --git a/android/app/src/main/cpp/xemu_android.cpp b/android/app/src/main/cpp/xemu_android.cpp index dade37cb33..fce15337d7 100644 --- a/android/app/src/main/cpp/xemu_android.cpp +++ b/android/app/src/main/cpp/xemu_android.cpp @@ -11,12 +11,10 @@ #include #include -#include #include #include #include #include -#include #include #include #include @@ -207,64 +205,24 @@ static std::string JStringToString(JNIEnv* env, jstring value) { return out; } -static std::string ToLowerAscii(std::string value) { - std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { - return static_cast(std::tolower(c)); - }); - return value; +static bool HasInlineAioCrashFlag(const std::string& flag_path) { + if (flag_path.empty()) { + return false; + } + struct stat st {}; + return stat(flag_path.c_str(), &st) == 0; } -static std::string GetBuildField(JNIEnv* env, const char* field_name) { - jclass buildClass = env->FindClass("android/os/Build"); - if (!buildClass) { - HasException(env, "Build class lookup"); - return {}; - } - jfieldID field = env->GetStaticFieldID(buildClass, field_name, "Ljava/lang/String;"); - if (!field) { - HasException(env, field_name); - env->DeleteLocalRef(buildClass); - return {}; - } - jstring value = - static_cast(env->GetStaticObjectField(buildClass, field)); - if (HasException(env, field_name)) { - env->DeleteLocalRef(buildClass); - return {}; - } - std::string out = JStringToString(env, value); - if (value) { - env->DeleteLocalRef(value); - } - env->DeleteLocalRef(buildClass); - return out; -} - -static bool ShouldEnableInlineAioWorkaround() { +static bool ShouldEnableInlineAioWorkaround(const std::string& crash_flag_path) { const char* forced = SDL_getenv("XEMU_ANDROID_INLINE_AIO"); if (forced) { return forced[0] != '\0' && forced[0] != '0'; } - JNIEnv* env = GetEnv(); - if (!env) { - return false; - } - - const std::string device = ToLowerAscii(GetBuildField(env, "DEVICE")); - const std::string product = ToLowerAscii(GetBuildField(env, "PRODUCT")); - const std::string model = ToLowerAscii(GetBuildField(env, "MODEL")); - - static const char* kAffectedDevices[] = { - "duchamp", - }; - - for (const char* marker : kAffectedDevices) { - if (device == marker || - product.find(marker) != std::string::npos || - model.find(marker) != std::string::npos) { - return true; - } + if (HasInlineAioCrashFlag(crash_flag_path)) { + LogInfoFmt("Inline AIO enabled from crash marker: %s", + crash_flag_path.c_str()); + return true; } return false; @@ -357,6 +315,7 @@ struct SetupFiles { std::string dvd; std::string eeprom; std::string config_path; + std::string inline_aio_flag_path; }; static bool WriteConfigToml(const std::string& config_path, @@ -473,6 +432,7 @@ static SetupFiles SyncSetupFiles() { std::string base = std::string(basePath) + "/x1box"; EnsureDirExists(base); out.eeprom = base + "/eeprom.bin"; + out.inline_aio_flag_path = base + "/inline_aio_required.flag"; const std::string mcpxPath = GetPrefString(env, activity, "mcpxPath"); const std::string flashPath = GetPrefString(env, activity, "flashPath"); @@ -556,6 +516,7 @@ extern "C" int (*qemu_main)(void); extern "C" void xemu_android_display_preinit(void); extern "C" void xemu_android_display_wait_ready(void); extern "C" void xemu_android_display_loop(void); +extern "C" void xemu_android_set_inline_aio_crash_flag_path(const char* path); struct QemuLaunchContext { int argc; @@ -601,14 +562,19 @@ extern "C" int SDL_main(int argc, char* argv[]) { SDL_GameControllerEventState(SDL_ENABLE); LoadGameControllerMappingsFromAssets(); + SetupFiles setup = SyncSetupFiles(); + + xemu_android_set_inline_aio_crash_flag_path(setup.inline_aio_flag_path.empty() + ? nullptr + : setup.inline_aio_flag_path.c_str()); + if (!SDL_getenv("XEMU_ANDROID_INLINE_AIO")) { - const bool use_inline_aio = ShouldEnableInlineAioWorkaround(); + const bool use_inline_aio = + ShouldEnableInlineAioWorkaround(setup.inline_aio_flag_path); setenv("XEMU_ANDROID_INLINE_AIO", use_inline_aio ? "1" : "0", 1); LogInfoFmt("XEMU_ANDROID_INLINE_AIO=%s", use_inline_aio ? "1" : "0"); } - SetupFiles setup = SyncSetupFiles(); - if (!setup.config_path.empty()) { LogInfo("SDL_main: loading config"); xemu_settings_set_path(setup.config_path.c_str());