From 5ef6123f03aa60ca17975744e220e87165f7b986 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 22 May 2026 18:42:51 +0500 Subject: [PATCH] engine: append log to the crash log on Android --- .../main/java/su/xash/engine/MainActivity.kt | 3 ++- .../java/su/xash/engine/util/CrashReports.kt | 6 ++++- engine/common/sys_con.c | 4 +-- engine/platform/posix/crash_posix.c | 25 +++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/su/xash/engine/MainActivity.kt b/android/app/src/main/java/su/xash/engine/MainActivity.kt index be11e2f9..88fab1f0 100644 --- a/android/app/src/main/java/su/xash/engine/MainActivity.kt +++ b/android/app/src/main/java/su/xash/engine/MainActivity.kt @@ -153,6 +153,7 @@ class MainActivity : AppCompatActivity() { moveOrCopy(pending, File(entryDir, CrashReports.STACKTRACE_NAME)) moveOrCopy(CrashReports.pendingSysinfo(this), File(entryDir, CrashReports.SYSINFO_NAME)) moveOrCopy(CrashReports.pendingIntent(this), File(entryDir, CrashReports.INTENT_NAME)) + moveOrCopy(CrashReports.pendingEngineLog(this), File(entryDir, CrashReports.ENGINELOG_NAME)) val entry = CrashReports.Entry(entryDir) AlertDialog.Builder(this) @@ -171,7 +172,7 @@ class MainActivity : AppCompatActivity() { if (src.renameTo(dst)) return - dst.writeText(src.readText()) + src.copyTo(dst, overwrite = true) src.delete() } diff --git a/android/app/src/main/java/su/xash/engine/util/CrashReports.kt b/android/app/src/main/java/su/xash/engine/util/CrashReports.kt index 90e9856b..2b2e0ef6 100644 --- a/android/app/src/main/java/su/xash/engine/util/CrashReports.kt +++ b/android/app/src/main/java/su/xash/engine/util/CrashReports.kt @@ -24,6 +24,7 @@ object CrashReports { const val STACKTRACE_NAME = "crash.log" const val SYSINFO_NAME = "sysinfo.txt" const val INTENT_NAME = "intent.txt" + const val ENGINELOG_NAME = "engine.log" class Entry(val dir: File) { val name: String get() = dir.name @@ -31,8 +32,9 @@ object CrashReports { val stacktrace: File get() = File(dir, STACKTRACE_NAME) val sysinfo: File get() = File(dir, SYSINFO_NAME) val intent: File get() = File(dir, INTENT_NAME) + val engineLog: File get() = File(dir, ENGINELOG_NAME) - fun attachments(): List = listOf(stacktrace, sysinfo, intent).filter { it.exists() && it.length() > 0 } + fun attachments(): List = listOf(stacktrace, sysinfo, intent, engineLog).filter { it.exists() && it.length() > 0 } fun summary(): String = buildString { if (stacktrace.exists()) @@ -52,6 +54,7 @@ object CrashReports { fun pendingStacktrace(ctx: Context): File = File(pendingDir(ctx), STACKTRACE_NAME) fun pendingSysinfo(ctx: Context): File = File(pendingDir(ctx), SYSINFO_NAME) fun pendingIntent(ctx: Context): File = File(pendingDir(ctx), INTENT_NAME) + fun pendingEngineLog(ctx: Context): File = File(pendingDir(ctx), ENGINELOG_NAME) fun historyDir(ctx: Context): File = File(ctx.filesDir, "crashes/history") // wipe everything on app update; otherwise drop logs older than 30 days @@ -65,6 +68,7 @@ object CrashReports { pendingStacktrace(ctx).delete() pendingSysinfo(ctx).delete() pendingIntent(ctx).delete() + pendingEngineLog(ctx).delete() prefs.edit().putInt(KEY_LAST_VERSION, currentVersion).apply() return } diff --git a/engine/common/sys_con.c b/engine/common/sys_con.c index e971b772..6c126b86 100644 --- a/engine/common/sys_con.c +++ b/engine/common/sys_con.c @@ -95,8 +95,8 @@ void Sys_InitLog( void ) const char *mode; if( host.change_game && host.type != HOST_DEDICATED ) - mode = "a"; - else mode = "w"; + mode = "a+"; + else mode = "w+"; if( Host_IsDedicated( )) Q_strncpy( s_ld.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_ld.title )); diff --git a/engine/platform/posix/crash_posix.c b/engine/platform/posix/crash_posix.c index 3965fb3b..35556a71 100644 --- a/engine/platform/posix/crash_posix.c +++ b/engine/platform/posix/crash_posix.c @@ -21,6 +21,7 @@ GNU General Public License for more details. #if XASH_ANDROID #include #include +#include #include #endif #include "library.h" @@ -29,6 +30,7 @@ GNU General Public License for more details. #if XASH_ANDROID static char crashlog_path[MAX_OSPATH]; +static char enginelog_path[MAX_OSPATH]; #endif static qboolean have_libbacktrace = false; @@ -79,6 +81,26 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context ) } } + // make a copy of engine.log in staging directory + // TODO: dump log from console buffers, if -log not enabled + if( logfd >= 0 && enginelog_path[0] && lseek( logfd, 0, SEEK_SET ) == 0 ) + { + int outfd = open( enginelog_path, O_WRONLY|O_CREAT|O_TRUNC, 0644 ); + if( outfd >= 0 ) + { + static char buf[8192]; + while( 1 ) + { + ssize_t n = read( logfd, buf, sizeof( buf )); + if( n <= 0 ) + break; + if( write( outfd, buf, (size_t)n ) != n ) + break; + } + close( outfd ); + } + } + // JNI/SDL calls aren't safe from a signal handler on Android _exit( 128 + signal ); #else @@ -115,7 +137,10 @@ void Sys_SetupCrashHandler( const char *argv0 ) const char *crashdir = getenv( "XASH3D_CRASH_DIR" ); if( !COM_StringEmptyOrNULL( crashdir )) + { Q_snprintf( crashlog_path, sizeof( crashlog_path ), "%s/crash.log", crashdir ); + Q_snprintf( enginelog_path, sizeof( enginelog_path ), "%s/engine.log", crashdir ); + } // unblock the engine/SDL_main thread just in case sigset_t set;